Merge "Add setDtimMultiplier() and its implementation."
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index 691cf34..7e682af 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -41,6 +41,7 @@
"android/hardware/audio/common/SinkMetadata.aidl",
"android/hardware/audio/common/SourceMetadata.aidl",
],
+ frozen: true,
imports: [
"android.media.audio.common.types-V2",
],
diff --git a/audio/aidl/TEST_MAPPING b/audio/aidl/TEST_MAPPING
index 6473d23..484320f 100644
--- a/audio/aidl/TEST_MAPPING
+++ b/audio/aidl/TEST_MAPPING
@@ -2,6 +2,18 @@
"presubmit": [
{
"name": "VtsHalAudioCoreTargetTest"
+ },
+ {
+ "name": "VtsHalAudioEffectFactoryTargetTest"
+ },
+ {
+ "name": "VtsHalAudioEffectTargetTest"
+ },
+ {
+ "name": "VtsHalEqualizerTargetTest"
+ },
+ {
+ "name": "VtsHalLoudnessEnhancerTargetTest"
}
]
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IConfig.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IConfig.aidl
index 163b7a0..9ce45bb 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IConfig.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IConfig.aidl
@@ -35,4 +35,5 @@
@VintfStability
interface IConfig {
android.hardware.audio.core.SurroundSoundConfig getSurroundSoundConfig();
+ android.media.audio.common.AudioHalEngineConfig getEngineConfig();
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl
index 979ebb8..09ad015 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl
@@ -36,6 +36,8 @@
union BassBoost {
android.hardware.audio.effect.VendorExtension vendor;
int strengthPm;
+ const int MIN_PER_MILLE_STRENGTH = 0;
+ const int MAX_PER_MILLE_STRENGTH = 1000;
@VintfStability
union Id {
int vendorExtensionTag;
diff --git a/audio/aidl/android/hardware/audio/core/IConfig.aidl b/audio/aidl/android/hardware/audio/core/IConfig.aidl
index c8ba6be..094d233 100644
--- a/audio/aidl/android/hardware/audio/core/IConfig.aidl
+++ b/audio/aidl/android/hardware/audio/core/IConfig.aidl
@@ -17,6 +17,7 @@
package android.hardware.audio.core;
import android.hardware.audio.core.SurroundSoundConfig;
+import android.media.audio.common.AudioHalEngineConfig;
/**
* This interface provides system-wide configuration parameters for audio I/O
@@ -34,4 +35,19 @@
* @return The surround sound configuration
*/
SurroundSoundConfig getSurroundSoundConfig();
+ /**
+ * Returns the configuration items used to determine the audio policy engine
+ * flavor and initial configuration.
+ *
+ * Engine flavor is determined by presence of capSpecificConfig, which must
+ * only be present if the device uses the Configurable Audio Policy (CAP)
+ * engine. Clients normally use the default audio policy engine. The client
+ * will use the CAP engine only when capSpecificConfig has a non-null value.
+ *
+ * This method is expected to only be called during the initialization of
+ * the audio policy engine, and must always return the same result.
+ *
+ * @return The engine configuration
+ */
+ AudioHalEngineConfig getEngineConfig();
}
diff --git a/audio/aidl/android/hardware/audio/effect/BassBoost.aidl b/audio/aidl/android/hardware/audio/effect/BassBoost.aidl
index 810c188..9e5d8aa 100644
--- a/audio/aidl/android/hardware/audio/effect/BassBoost.aidl
+++ b/audio/aidl/android/hardware/audio/effect/BassBoost.aidl
@@ -59,6 +59,16 @@
}
/**
+ * Minimal possible per mille strength.
+ */
+ const int MIN_PER_MILLE_STRENGTH = 0;
+
+ /**
+ * Maximum possible per mille strength.
+ */
+ const int MAX_PER_MILLE_STRENGTH = 1000;
+
+ /**
* The per mille strength of the bass boost effect.
*
* If the implementation does not support per mille accuracy for setting the strength, it is
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 2b9ed5b..f2cebbf 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -18,11 +18,14 @@
"libfmq",
"libstagefright_foundation",
"libutils",
+ "libxml2",
"android.hardware.common-V2-ndk",
"android.hardware.common.fmq-V1-ndk",
],
header_libs: [
+ "libaudio_system_headers",
"libaudioaidl_headers",
+ "libxsdc-utils",
],
}
@@ -35,12 +38,26 @@
],
export_include_dirs: ["include"],
srcs: [
+ "AudioPolicyConfigXmlConverter.cpp",
"Config.cpp",
"Configuration.cpp",
+ "EngineConfigXmlConverter.cpp",
"Module.cpp",
"Stream.cpp",
"Telephony.cpp",
],
+ generated_sources: [
+ "audio_policy_configuration_aidl_default",
+ "audio_policy_engine_configuration_aidl_default",
+ ],
+ generated_headers: [
+ "audio_policy_configuration_aidl_default",
+ "audio_policy_engine_configuration_aidl_default",
+ ],
+ export_generated_headers: [
+ "audio_policy_configuration_aidl_default",
+ "audio_policy_engine_configuration_aidl_default",
+ ],
visibility: [
":__subpackages__",
],
diff --git a/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp b/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp
new file mode 100644
index 0000000..6290912
--- /dev/null
+++ b/audio/aidl/default/AudioPolicyConfigXmlConverter.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+#include <functional>
+#include <unordered_map>
+
+#include <aidl/android/media/audio/common/AudioHalEngineConfig.h>
+#include <system/audio-base-utils.h>
+
+#include "core-impl/AudioPolicyConfigXmlConverter.h"
+
+using aidl::android::media::audio::common::AudioHalEngineConfig;
+using aidl::android::media::audio::common::AudioHalVolumeCurve;
+using aidl::android::media::audio::common::AudioHalVolumeGroup;
+using aidl::android::media::audio::common::AudioStreamType;
+
+namespace xsd = android::audio::policy::configuration;
+
+namespace aidl::android::hardware::audio::core::internal {
+
+static const int kDefaultVolumeIndexMin = 0;
+static const int kDefaultVolumeIndexMax = 100;
+static const int KVolumeIndexDeferredToAudioService = -1;
+/**
+ * Valid curve points take the form "<index>,<attenuationMb>", where the index
+ * must be in the range [0,100]. kInvalidCurvePointIndex is used to indicate
+ * that a point was formatted incorrectly (e.g. if a vendor accidentally typed a
+ * '.' instead of a ',' in their XML) -- using such a curve point will result in
+ * failed VTS tests.
+ */
+static const int8_t kInvalidCurvePointIndex = -1;
+
+AudioHalVolumeCurve::CurvePoint AudioPolicyConfigXmlConverter::convertCurvePointToAidl(
+ const std::string& xsdcCurvePoint) {
+ AudioHalVolumeCurve::CurvePoint aidlCurvePoint{};
+ if (sscanf(xsdcCurvePoint.c_str(), "%" SCNd8 ",%d", &aidlCurvePoint.index,
+ &aidlCurvePoint.attenuationMb) != 2) {
+ aidlCurvePoint.index = kInvalidCurvePointIndex;
+ }
+ return aidlCurvePoint;
+}
+
+AudioHalVolumeCurve AudioPolicyConfigXmlConverter::convertVolumeCurveToAidl(
+ const xsd::Volume& xsdcVolumeCurve) {
+ AudioHalVolumeCurve aidlVolumeCurve;
+ aidlVolumeCurve.deviceCategory =
+ static_cast<AudioHalVolumeCurve::DeviceCategory>(xsdcVolumeCurve.getDeviceCategory());
+ if (xsdcVolumeCurve.hasRef()) {
+ if (mVolumesReferenceMap.empty()) {
+ mVolumesReferenceMap = generateReferenceMap<xsd::Volumes, xsd::Reference>(
+ getXsdcConfig()->getVolumes());
+ }
+ aidlVolumeCurve.curvePoints =
+ convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
+ mVolumesReferenceMap.at(xsdcVolumeCurve.getRef()).getPoint(),
+ std::bind(&AudioPolicyConfigXmlConverter::convertCurvePointToAidl, this,
+ std::placeholders::_1));
+ } else {
+ aidlVolumeCurve.curvePoints =
+ convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
+ xsdcVolumeCurve.getPoint(),
+ std::bind(&AudioPolicyConfigXmlConverter::convertCurvePointToAidl, this,
+ std::placeholders::_1));
+ }
+ return aidlVolumeCurve;
+}
+
+void AudioPolicyConfigXmlConverter::mapStreamToVolumeCurve(const xsd::Volume& xsdcVolumeCurve) {
+ mStreamToVolumeCurvesMap[xsdcVolumeCurve.getStream()].push_back(
+ convertVolumeCurveToAidl(xsdcVolumeCurve));
+}
+
+const AudioHalEngineConfig& AudioPolicyConfigXmlConverter::getAidlEngineConfig() {
+ if (mAidlEngineConfig.volumeGroups.empty() && getXsdcConfig() &&
+ getXsdcConfig()->hasVolumes()) {
+ parseVolumes();
+ }
+ return mAidlEngineConfig;
+}
+
+void AudioPolicyConfigXmlConverter::mapStreamsToVolumeCurves() {
+ if (getXsdcConfig()->hasVolumes()) {
+ for (const xsd::Volumes& xsdcWrapperType : getXsdcConfig()->getVolumes()) {
+ for (const xsd::Volume& xsdcVolume : xsdcWrapperType.getVolume()) {
+ mapStreamToVolumeCurve(xsdcVolume);
+ }
+ }
+ }
+}
+
+void AudioPolicyConfigXmlConverter::addVolumeGroupstoEngineConfig() {
+ for (const auto& [xsdcStream, volumeCurves] : mStreamToVolumeCurvesMap) {
+ AudioHalVolumeGroup volumeGroup;
+ volumeGroup.name = xsd::toString(xsdcStream);
+ if (static_cast<int>(xsdcStream) >= AUDIO_STREAM_PUBLIC_CNT) {
+ volumeGroup.minIndex = kDefaultVolumeIndexMin;
+ volumeGroup.maxIndex = kDefaultVolumeIndexMax;
+ } else {
+ volumeGroup.minIndex = KVolumeIndexDeferredToAudioService;
+ volumeGroup.maxIndex = KVolumeIndexDeferredToAudioService;
+ }
+ volumeGroup.volumeCurves = volumeCurves;
+ mAidlEngineConfig.volumeGroups.push_back(std::move(volumeGroup));
+ }
+}
+
+void AudioPolicyConfigXmlConverter::parseVolumes() {
+ if (mStreamToVolumeCurvesMap.empty() && getXsdcConfig()->hasVolumes()) {
+ mapStreamsToVolumeCurves();
+ addVolumeGroupstoEngineConfig();
+ }
+}
+} // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/Config.cpp b/audio/aidl/default/Config.cpp
index 0fdd5b4..87c0ace 100644
--- a/audio/aidl/default/Config.cpp
+++ b/audio/aidl/default/Config.cpp
@@ -13,10 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#define LOG_TAG "AHAL_Module"
+
+#define LOG_TAG "AHAL_Config"
#include <android-base/logging.h>
+#include <system/audio_config.h>
+
+#include "core-impl/AudioPolicyConfigXmlConverter.h"
#include "core-impl/Config.h"
+#include "core-impl/EngineConfigXmlConverter.h"
+
+using aidl::android::media::audio::common::AudioHalEngineConfig;
namespace aidl::android::hardware::audio::core {
ndk::ScopedAStatus Config::getSurroundSoundConfig(SurroundSoundConfig* _aidl_return) {
@@ -26,4 +33,24 @@
LOG(DEBUG) << __func__ << ": returning " << _aidl_return->toString();
return ndk::ScopedAStatus::ok();
}
+
+ndk::ScopedAStatus Config::getEngineConfig(AudioHalEngineConfig* _aidl_return) {
+ static const AudioHalEngineConfig returnEngCfg = [this]() {
+ AudioHalEngineConfig engConfig;
+ if (mEngConfigConverter.getStatus() == ::android::OK) {
+ engConfig = mEngConfigConverter.getAidlEngineConfig();
+ } else {
+ LOG(INFO) << __func__ << mEngConfigConverter.getError();
+ if (mAudioPolicyConverter.getStatus() == ::android::OK) {
+ engConfig = mAudioPolicyConverter.getAidlEngineConfig();
+ } else {
+ LOG(WARNING) << __func__ << mAudioPolicyConverter.getError();
+ }
+ }
+ return engConfig;
+ }();
+ *_aidl_return = returnEngCfg;
+ LOG(DEBUG) << __func__ << ": returning " << _aidl_return->toString();
+ return ndk::ScopedAStatus::ok();
+}
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/EffectImpl.cpp b/audio/aidl/default/EffectImpl.cpp
index 2754bb6..0d40cce 100644
--- a/audio/aidl/default/EffectImpl.cpp
+++ b/audio/aidl/default/EffectImpl.cpp
@@ -25,41 +25,33 @@
const std::optional<Parameter::Specific>& specific,
OpenEffectReturn* ret) {
LOG(DEBUG) << __func__;
- {
- std::lock_guard lg(mMutex);
- RETURN_OK_IF(mState != State::INIT);
- mContext = createContext(common);
- RETURN_IF(!mContext, EX_ILLEGAL_ARGUMENT, "createContextFailed");
- setContext(mContext);
- }
+ RETURN_OK_IF(mState != State::INIT);
+ auto context = createContext(common);
+ RETURN_IF(!context, EX_NULL_POINTER, "createContextFailed");
RETURN_IF_ASTATUS_NOT_OK(setParameterCommon(common), "setCommParamErr");
if (specific.has_value()) {
RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(specific.value()), "setSpecParamErr");
}
- RETURN_IF(createThread(LOG_TAG) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
+ mState = State::IDLE;
+ context->dupeFmq(ret);
+ RETURN_IF(createThread(context, getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
"FailedToCreateWorker");
-
- {
- std::lock_guard lg(mMutex);
- mContext->dupeFmq(ret);
- mState = State::IDLE;
- }
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus EffectImpl::close() {
- std::lock_guard lg(mMutex);
RETURN_OK_IF(mState == State::INIT);
RETURN_IF(mState == State::PROCESSING, EX_ILLEGAL_STATE, "closeAtProcessing");
// stop the worker thread, ignore the return code
RETURN_IF(destroyThread() != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
"FailedToDestroyWorker");
+ mState = State::INIT;
RETURN_IF(releaseContext() != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
"FailedToCreateWorker");
- mState = State::INIT;
+
LOG(DEBUG) << __func__;
return ndk::ScopedAStatus::ok();
}
@@ -113,29 +105,30 @@
}
ndk::ScopedAStatus EffectImpl::setParameterCommon(const Parameter& param) {
- std::lock_guard lg(mMutex);
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ auto context = getContext();
+ RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
+
auto tag = param.getTag();
switch (tag) {
case Parameter::common:
- RETURN_IF(mContext->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
+ RETURN_IF(context->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "setCommFailed");
break;
case Parameter::deviceDescription:
- RETURN_IF(mContext->setOutputDevice(param.get<Parameter::deviceDescription>()) !=
+ RETURN_IF(context->setOutputDevice(param.get<Parameter::deviceDescription>()) !=
RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "setDeviceFailed");
break;
case Parameter::mode:
- RETURN_IF(mContext->setAudioMode(param.get<Parameter::mode>()) != RetCode::SUCCESS,
+ RETURN_IF(context->setAudioMode(param.get<Parameter::mode>()) != RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "setModeFailed");
break;
case Parameter::source:
- RETURN_IF(mContext->setAudioSource(param.get<Parameter::source>()) != RetCode::SUCCESS,
+ RETURN_IF(context->setAudioSource(param.get<Parameter::source>()) != RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "setSourceFailed");
break;
case Parameter::volumeStereo:
- RETURN_IF(mContext->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
+ RETURN_IF(context->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "setVolumeStereoFailed");
break;
@@ -149,27 +142,28 @@
}
ndk::ScopedAStatus EffectImpl::getParameterCommon(const Parameter::Tag& tag, Parameter* param) {
- std::lock_guard lg(mMutex);
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ auto context = getContext();
+ RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
+
switch (tag) {
case Parameter::common: {
- param->set<Parameter::common>(mContext->getCommon());
+ param->set<Parameter::common>(context->getCommon());
break;
}
case Parameter::deviceDescription: {
- param->set<Parameter::deviceDescription>(mContext->getOutputDevice());
+ param->set<Parameter::deviceDescription>(context->getOutputDevice());
break;
}
case Parameter::mode: {
- param->set<Parameter::mode>(mContext->getAudioMode());
+ param->set<Parameter::mode>(context->getAudioMode());
break;
}
case Parameter::source: {
- param->set<Parameter::source>(mContext->getAudioSource());
+ param->set<Parameter::source>(context->getAudioSource());
break;
}
case Parameter::volumeStereo: {
- param->set<Parameter::volumeStereo>(mContext->getVolumeStereo());
+ param->set<Parameter::volumeStereo>(context->getVolumeStereo());
break;
}
default: {
@@ -182,39 +176,30 @@
}
ndk::ScopedAStatus EffectImpl::getState(State* state) {
- std::lock_guard lg(mMutex);
*state = mState;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus EffectImpl::command(CommandId command) {
- std::lock_guard lg(mMutex);
+ RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "CommandStateError");
LOG(DEBUG) << __func__ << ": receive command: " << toString(command) << " at state "
<< toString(mState);
- RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "CommandStateError");
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
switch (command) {
case CommandId::START:
RETURN_IF(mState == State::INIT, EX_ILLEGAL_STATE, "instanceNotOpen");
RETURN_OK_IF(mState == State::PROCESSING);
- RETURN_IF_ASTATUS_NOT_OK(commandStart(), "commandStartFailed");
- mState = State::PROCESSING;
+ RETURN_IF_ASTATUS_NOT_OK(commandImpl(command), "commandImplFailed");
startThread();
- return ndk::ScopedAStatus::ok();
+ mState = State::PROCESSING;
+ break;
case CommandId::STOP:
- RETURN_OK_IF(mState == State::IDLE);
- mState = State::IDLE;
- RETURN_IF_ASTATUS_NOT_OK(commandStop(), "commandStopFailed");
- stopThread();
- return ndk::ScopedAStatus::ok();
case CommandId::RESET:
RETURN_OK_IF(mState == State::IDLE);
- mState = State::IDLE;
- RETURN_IF_ASTATUS_NOT_OK(commandStop(), "commandStopFailed");
stopThread();
- mContext->resetBuffer();
- return ndk::ScopedAStatus::ok();
+ RETURN_IF_ASTATUS_NOT_OK(commandImpl(command), "commandImplFailed");
+ mState = State::IDLE;
+ break;
default:
LOG(ERROR) << __func__ << " instance still processing";
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
@@ -224,6 +209,15 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus EffectImpl::commandImpl(CommandId command) {
+ auto context = getContext();
+ RETURN_IF(!context, EX_NULL_POINTER, "nullContext");
+ if (command == CommandId::RESET) {
+ context->resetBuffer();
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
void EffectImpl::cleanUp() {
command(CommandId::STOP);
close();
@@ -238,19 +232,12 @@
}
// A placeholder processing implementation to copy samples from input to output
-IEffect::Status EffectImpl::effectProcessImpl(float* in, float* out, int processSamples) {
- // lock before access context/parameters
- std::lock_guard lg(mMutex);
- IEffect::Status status = {EX_NULL_POINTER, 0, 0};
- RETURN_VALUE_IF(!mContext, status, "nullContext");
- auto frameSize = mContext->getInputFrameSize();
- RETURN_VALUE_IF(0 == frameSize, status, "frameSizeIs0");
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << processSamples
- << " frames " << processSamples * sizeof(float) / frameSize;
- for (int i = 0; i < processSamples; i++) {
+IEffect::Status EffectImpl::effectProcessImpl(float* in, float* out, int samples) {
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- LOG(DEBUG) << __func__ << " done processing " << processSamples << " samples";
- return {STATUS_OK, processSamples, processSamples};
+ LOG(DEBUG) << __func__ << " done processing " << samples << " samples";
+ return {STATUS_OK, samples, samples};
}
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EffectThread.cpp b/audio/aidl/default/EffectThread.cpp
index 80f120b..2b3513d 100644
--- a/audio/aidl/default/EffectThread.cpp
+++ b/audio/aidl/default/EffectThread.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <memory>
#define LOG_TAG "AHAL_EffectThread"
#include <android-base/logging.h>
#include <pthread.h>
@@ -32,13 +33,18 @@
LOG(DEBUG) << __func__ << " done";
};
-RetCode EffectThread::createThread(const std::string& name, const int priority) {
+RetCode EffectThread::createThread(std::shared_ptr<EffectContext> context, const std::string& name,
+ const int priority) {
if (mThread.joinable()) {
LOG(WARNING) << __func__ << " thread already created, no-op";
return RetCode::SUCCESS;
}
mName = name;
mPriority = priority;
+ {
+ std::lock_guard lg(mThreadMutex);
+ mThreadContext = std::move(context);
+ }
mThread = std::thread(&EffectThread::threadLoop, this);
LOG(DEBUG) << __func__ << " " << name << " priority " << mPriority << " done";
return RetCode::SUCCESS;
@@ -46,7 +52,7 @@
RetCode EffectThread::destroyThread() {
{
- std::lock_guard lg(mMutex);
+ std::lock_guard lg(mThreadMutex);
mStop = mExit = true;
}
mCv.notify_one();
@@ -54,6 +60,11 @@
if (mThread.joinable()) {
mThread.join();
}
+
+ {
+ std::lock_guard lg(mThreadMutex);
+ mThreadContext.reset();
+ }
LOG(DEBUG) << __func__ << " done";
return RetCode::SUCCESS;
}
@@ -65,7 +76,7 @@
}
{
- std::lock_guard lg(mMutex);
+ std::lock_guard lg(mThreadMutex);
if (!mStop) {
LOG(WARNING) << __func__ << " already start";
return RetCode::SUCCESS;
@@ -85,7 +96,7 @@
}
{
- std::lock_guard lg(mMutex);
+ std::lock_guard lg(mThreadMutex);
if (mStop) {
LOG(WARNING) << __func__ << " already stop";
return RetCode::SUCCESS;
@@ -97,13 +108,13 @@
}
void EffectThread::threadLoop() {
- pthread_setname_np(pthread_self(), mName.substr(0, MAX_TASK_COMM_LEN - 1).c_str());
+ pthread_setname_np(pthread_self(), mName.substr(0, kMaxTaskNameLen - 1).c_str());
setpriority(PRIO_PROCESS, 0, mPriority);
while (true) {
bool needExit = false;
{
- std::unique_lock l(mMutex);
- mCv.wait(l, [&]() REQUIRES(mMutex) {
+ std::unique_lock l(mThreadMutex);
+ mCv.wait(l, [&]() REQUIRES(mThreadMutex) {
needExit = mExit;
return mExit || !mStop;
});
@@ -112,9 +123,41 @@
LOG(WARNING) << __func__ << " EXIT!";
return;
}
- // process without lock
+
process();
}
}
+void EffectThread::process() {
+ std::shared_ptr<EffectContext> context;
+ {
+ std::lock_guard lg(mThreadMutex);
+ context = mThreadContext;
+ RETURN_VALUE_IF(!context, void(), "nullContext");
+ }
+ std::shared_ptr<EffectContext::StatusMQ> statusMQ = context->getStatusFmq();
+ std::shared_ptr<EffectContext::DataMQ> inputMQ = context->getInputDataFmq();
+ std::shared_ptr<EffectContext::DataMQ> outputMQ = context->getOutputDataFmq();
+ auto buffer = context->getWorkBuffer();
+
+ // Only this worker will read from input data MQ and write to output data MQ.
+ auto readSamples = inputMQ->availableToRead(), writeSamples = outputMQ->availableToWrite();
+ if (readSamples && writeSamples) {
+ auto processSamples = std::min(readSamples, writeSamples);
+ LOG(DEBUG) << __func__ << " available to read " << readSamples << " available to write "
+ << writeSamples << " process " << processSamples;
+
+ inputMQ->read(buffer, processSamples);
+
+ // call effectProcessImpl without lock
+ IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples);
+ outputMQ->write(buffer, status.fmqProduced);
+ statusMQ->writeBlocking(&status, 1);
+ LOG(DEBUG) << __func__ << " done processing, effect consumed " << status.fmqConsumed
+ << " produced " << status.fmqProduced;
+ } else {
+ // TODO: maybe add some sleep here to avoid busy waiting
+ }
+}
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/EngineConfigXmlConverter.cpp b/audio/aidl/default/EngineConfigXmlConverter.cpp
new file mode 100644
index 0000000..71b4b0e
--- /dev/null
+++ b/audio/aidl/default/EngineConfigXmlConverter.cpp
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <unistd.h>
+#include <functional>
+#include <unordered_map>
+
+#include <aidl/android/media/audio/common/AudioHalEngineConfig.h>
+
+#include "core-impl/EngineConfigXmlConverter.h"
+
+using aidl::android::media::audio::common::AudioAttributes;
+using aidl::android::media::audio::common::AudioContentType;
+using aidl::android::media::audio::common::AudioFlag;
+using aidl::android::media::audio::common::AudioHalAttributesGroup;
+using aidl::android::media::audio::common::AudioHalCapCriterion;
+using aidl::android::media::audio::common::AudioHalCapCriterionType;
+using aidl::android::media::audio::common::AudioHalEngineConfig;
+using aidl::android::media::audio::common::AudioHalProductStrategy;
+using aidl::android::media::audio::common::AudioHalVolumeCurve;
+using aidl::android::media::audio::common::AudioHalVolumeGroup;
+using aidl::android::media::audio::common::AudioProductStrategyType;
+using aidl::android::media::audio::common::AudioSource;
+using aidl::android::media::audio::common::AudioStreamType;
+using aidl::android::media::audio::common::AudioUsage;
+
+namespace xsd = android::audio::policy::engine::configuration;
+
+namespace aidl::android::hardware::audio::core::internal {
+
+/**
+ * Valid curve points take the form "<index>,<attenuationMb>", where the index
+ * must be in the range [0,100]. kInvalidCurvePointIndex is used to indicate
+ * that a point was formatted incorrectly (e.g. if a vendor accidentally typed a
+ * '.' instead of a ',' in their XML)-- using such a curve point will result in
+ * failed VTS tests.
+ */
+static const int8_t kInvalidCurvePointIndex = -1;
+
+void EngineConfigXmlConverter::initProductStrategyMap() {
+#define STRATEGY_ENTRY(name) {"STRATEGY_" #name, static_cast<int>(AudioProductStrategyType::name)}
+
+ mProductStrategyMap = {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
+}
+
+int EngineConfigXmlConverter::convertProductStrategyNameToAidl(
+ const std::string& xsdcProductStrategyName) {
+ const auto [it, success] = mProductStrategyMap.insert(
+ std::make_pair(xsdcProductStrategyName, mNextVendorStrategy));
+ if (success) {
+ mNextVendorStrategy++;
+ }
+ return it->second;
+}
+
+bool isDefaultAudioAttributes(const AudioAttributes& attributes) {
+ return ((attributes.contentType == AudioContentType::UNKNOWN) &&
+ (attributes.usage == AudioUsage::UNKNOWN) &&
+ (attributes.source == AudioSource::DEFAULT) && (attributes.flags == 0) &&
+ (attributes.tags.empty()));
+}
+
+AudioAttributes EngineConfigXmlConverter::convertAudioAttributesToAidl(
+ const xsd::AttributesType& xsdcAudioAttributes) {
+ if (xsdcAudioAttributes.hasAttributesRef()) {
+ if (mAttributesReferenceMap.empty()) {
+ mAttributesReferenceMap =
+ generateReferenceMap<xsd::AttributesRef, xsd::AttributesRefType>(
+ getXsdcConfig()->getAttributesRef());
+ }
+ return convertAudioAttributesToAidl(
+ *(mAttributesReferenceMap.at(xsdcAudioAttributes.getAttributesRef())
+ .getFirstAttributes()));
+ }
+ AudioAttributes aidlAudioAttributes;
+ if (xsdcAudioAttributes.hasContentType()) {
+ aidlAudioAttributes.contentType = static_cast<AudioContentType>(
+ xsdcAudioAttributes.getFirstContentType()->getValue());
+ }
+ if (xsdcAudioAttributes.hasUsage()) {
+ aidlAudioAttributes.usage =
+ static_cast<AudioUsage>(xsdcAudioAttributes.getFirstUsage()->getValue());
+ }
+ if (xsdcAudioAttributes.hasSource()) {
+ aidlAudioAttributes.source =
+ static_cast<AudioSource>(xsdcAudioAttributes.getFirstSource()->getValue());
+ }
+ if (xsdcAudioAttributes.hasFlags()) {
+ std::vector<xsd::FlagType> xsdcFlagTypeVec =
+ xsdcAudioAttributes.getFirstFlags()->getValue();
+ for (const xsd::FlagType& xsdcFlagType : xsdcFlagTypeVec) {
+ if (xsdcFlagType != xsd::FlagType::AUDIO_FLAG_NONE) {
+ aidlAudioAttributes.flags |= 1 << (static_cast<int>(xsdcFlagType) - 1);
+ }
+ }
+ }
+ if (xsdcAudioAttributes.hasBundle()) {
+ const xsd::BundleType* xsdcBundle = xsdcAudioAttributes.getFirstBundle();
+ aidlAudioAttributes.tags[0] = xsdcBundle->getKey() + "=" + xsdcBundle->getValue();
+ }
+ if (isDefaultAudioAttributes(aidlAudioAttributes)) {
+ mDefaultProductStrategyId = std::optional<int>{-1};
+ }
+ return aidlAudioAttributes;
+}
+
+AudioHalAttributesGroup EngineConfigXmlConverter::convertAttributesGroupToAidl(
+ const xsd::AttributesGroup& xsdcAttributesGroup) {
+ AudioHalAttributesGroup aidlAttributesGroup;
+ static const int kStreamTypeEnumOffset =
+ static_cast<int>(xsd::Stream::AUDIO_STREAM_VOICE_CALL) -
+ static_cast<int>(AudioStreamType::VOICE_CALL);
+ aidlAttributesGroup.streamType = static_cast<AudioStreamType>(
+ static_cast<int>(xsdcAttributesGroup.getStreamType()) - kStreamTypeEnumOffset);
+ aidlAttributesGroup.volumeGroupName = xsdcAttributesGroup.getVolumeGroup();
+ if (xsdcAttributesGroup.hasAttributes_optional()) {
+ aidlAttributesGroup.attributes =
+ convertCollectionToAidl<xsd::AttributesType, AudioAttributes>(
+ xsdcAttributesGroup.getAttributes_optional(),
+ std::bind(&EngineConfigXmlConverter::convertAudioAttributesToAidl, this,
+ std::placeholders::_1));
+ } else if (xsdcAttributesGroup.hasContentType_optional() ||
+ xsdcAttributesGroup.hasUsage_optional() ||
+ xsdcAttributesGroup.hasSource_optional() ||
+ xsdcAttributesGroup.hasFlags_optional() ||
+ xsdcAttributesGroup.hasBundle_optional()) {
+ aidlAttributesGroup.attributes.push_back(convertAudioAttributesToAidl(xsd::AttributesType(
+ xsdcAttributesGroup.getContentType_optional(),
+ xsdcAttributesGroup.getUsage_optional(), xsdcAttributesGroup.getSource_optional(),
+ xsdcAttributesGroup.getFlags_optional(), xsdcAttributesGroup.getBundle_optional(),
+ std::nullopt)));
+
+ } else {
+ // do nothing;
+ // TODO: check if this is valid or if we should treat as an error.
+ // Currently, attributes are not mandatory in schema, but an AttributesGroup
+ // without attributes does not make much sense.
+ }
+ return aidlAttributesGroup;
+}
+
+AudioHalProductStrategy EngineConfigXmlConverter::convertProductStrategyToAidl(
+ const xsd::ProductStrategies::ProductStrategy& xsdcProductStrategy) {
+ AudioHalProductStrategy aidlProductStrategy;
+
+ aidlProductStrategy.id = convertProductStrategyNameToAidl(xsdcProductStrategy.getName());
+
+ if (xsdcProductStrategy.hasAttributesGroup()) {
+ aidlProductStrategy.attributesGroups =
+ convertCollectionToAidl<xsd::AttributesGroup, AudioHalAttributesGroup>(
+ xsdcProductStrategy.getAttributesGroup(),
+ std::bind(&EngineConfigXmlConverter::convertAttributesGroupToAidl, this,
+ std::placeholders::_1));
+ }
+ if ((mDefaultProductStrategyId != std::nullopt) && (mDefaultProductStrategyId.value() == -1)) {
+ mDefaultProductStrategyId = aidlProductStrategy.id;
+ }
+ return aidlProductStrategy;
+}
+
+AudioHalVolumeCurve::CurvePoint EngineConfigXmlConverter::convertCurvePointToAidl(
+ const std::string& xsdcCurvePoint) {
+ AudioHalVolumeCurve::CurvePoint aidlCurvePoint{};
+ if (sscanf(xsdcCurvePoint.c_str(), "%" SCNd8 ",%d", &aidlCurvePoint.index,
+ &aidlCurvePoint.attenuationMb) != 2) {
+ aidlCurvePoint.index = kInvalidCurvePointIndex;
+ }
+ return aidlCurvePoint;
+}
+
+AudioHalVolumeCurve EngineConfigXmlConverter::convertVolumeCurveToAidl(
+ const xsd::Volume& xsdcVolumeCurve) {
+ AudioHalVolumeCurve aidlVolumeCurve;
+ aidlVolumeCurve.deviceCategory =
+ static_cast<AudioHalVolumeCurve::DeviceCategory>(xsdcVolumeCurve.getDeviceCategory());
+ if (xsdcVolumeCurve.hasRef()) {
+ if (mVolumesReferenceMap.empty()) {
+ mVolumesReferenceMap = generateReferenceMap<xsd::VolumesType, xsd::VolumeRef>(
+ getXsdcConfig()->getVolumes());
+ }
+ aidlVolumeCurve.curvePoints =
+ convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
+ mVolumesReferenceMap.at(xsdcVolumeCurve.getRef()).getPoint(),
+ std::bind(&EngineConfigXmlConverter::convertCurvePointToAidl, this,
+ std::placeholders::_1));
+ } else {
+ aidlVolumeCurve.curvePoints =
+ convertCollectionToAidl<std::string, AudioHalVolumeCurve::CurvePoint>(
+ xsdcVolumeCurve.getPoint(),
+ std::bind(&EngineConfigXmlConverter::convertCurvePointToAidl, this,
+ std::placeholders::_1));
+ }
+ return aidlVolumeCurve;
+}
+
+AudioHalVolumeGroup EngineConfigXmlConverter::convertVolumeGroupToAidl(
+ const xsd::VolumeGroupsType::VolumeGroup& xsdcVolumeGroup) {
+ AudioHalVolumeGroup aidlVolumeGroup;
+ aidlVolumeGroup.name = xsdcVolumeGroup.getName();
+ aidlVolumeGroup.minIndex = xsdcVolumeGroup.getIndexMin();
+ aidlVolumeGroup.maxIndex = xsdcVolumeGroup.getIndexMax();
+ aidlVolumeGroup.volumeCurves = convertCollectionToAidl<xsd::Volume, AudioHalVolumeCurve>(
+ xsdcVolumeGroup.getVolume(),
+ std::bind(&EngineConfigXmlConverter::convertVolumeCurveToAidl, this,
+ std::placeholders::_1));
+ return aidlVolumeGroup;
+}
+
+AudioHalCapCriterion EngineConfigXmlConverter::convertCapCriterionToAidl(
+ const xsd::CriterionType& xsdcCriterion) {
+ AudioHalCapCriterion aidlCapCriterion;
+ aidlCapCriterion.name = xsdcCriterion.getName();
+ aidlCapCriterion.criterionTypeName = xsdcCriterion.getType();
+ aidlCapCriterion.defaultLiteralValue = xsdcCriterion.get_default();
+ return aidlCapCriterion;
+}
+
+std::string EngineConfigXmlConverter::convertCriterionTypeValueToAidl(
+ const xsd::ValueType& xsdcCriterionTypeValue) {
+ return xsdcCriterionTypeValue.getLiteral();
+}
+
+AudioHalCapCriterionType EngineConfigXmlConverter::convertCapCriterionTypeToAidl(
+ const xsd::CriterionTypeType& xsdcCriterionType) {
+ AudioHalCapCriterionType aidlCapCriterionType;
+ aidlCapCriterionType.name = xsdcCriterionType.getName();
+ aidlCapCriterionType.isInclusive = !(static_cast<bool>(xsdcCriterionType.getType()));
+ aidlCapCriterionType.values =
+ convertWrappedCollectionToAidl<xsd::ValuesType, xsd::ValueType, std::string>(
+ xsdcCriterionType.getValues(), &xsd::ValuesType::getValue,
+ std::bind(&EngineConfigXmlConverter::convertCriterionTypeValueToAidl, this,
+ std::placeholders::_1));
+ return aidlCapCriterionType;
+}
+
+AudioHalEngineConfig& EngineConfigXmlConverter::getAidlEngineConfig() {
+ return mAidlEngineConfig;
+}
+
+void EngineConfigXmlConverter::init() {
+ initProductStrategyMap();
+ if (getXsdcConfig()->hasProductStrategies()) {
+ mAidlEngineConfig.productStrategies =
+ convertWrappedCollectionToAidl<xsd::ProductStrategies,
+ xsd::ProductStrategies::ProductStrategy,
+ AudioHalProductStrategy>(
+ getXsdcConfig()->getProductStrategies(),
+ &xsd::ProductStrategies::getProductStrategy,
+ std::bind(&EngineConfigXmlConverter::convertProductStrategyToAidl, this,
+ std::placeholders::_1));
+ if (mDefaultProductStrategyId) {
+ mAidlEngineConfig.defaultProductStrategyId = mDefaultProductStrategyId.value();
+ }
+ }
+ if (getXsdcConfig()->hasVolumeGroups()) {
+ mAidlEngineConfig.volumeGroups = convertWrappedCollectionToAidl<
+ xsd::VolumeGroupsType, xsd::VolumeGroupsType::VolumeGroup, AudioHalVolumeGroup>(
+ getXsdcConfig()->getVolumeGroups(), &xsd::VolumeGroupsType::getVolumeGroup,
+ std::bind(&EngineConfigXmlConverter::convertVolumeGroupToAidl, this,
+ std::placeholders::_1));
+ }
+ if (getXsdcConfig()->hasCriteria() && getXsdcConfig()->hasCriterion_types()) {
+ AudioHalEngineConfig::CapSpecificConfig capSpecificConfig;
+ capSpecificConfig.criteria =
+ convertWrappedCollectionToAidl<xsd::CriteriaType, xsd::CriterionType,
+ AudioHalCapCriterion>(
+ getXsdcConfig()->getCriteria(), &xsd::CriteriaType::getCriterion,
+ std::bind(&EngineConfigXmlConverter::convertCapCriterionToAidl, this,
+ std::placeholders::_1));
+ capSpecificConfig.criterionTypes =
+ convertWrappedCollectionToAidl<xsd::CriterionTypesType, xsd::CriterionTypeType,
+ AudioHalCapCriterionType>(
+ getXsdcConfig()->getCriterion_types(),
+ &xsd::CriterionTypesType::getCriterion_type,
+ std::bind(&EngineConfigXmlConverter::convertCapCriterionTypeToAidl, this,
+ std::placeholders::_1));
+ mAidlEngineConfig.capSpecificConfig = capSpecificConfig;
+ }
+}
+} // namespace aidl::android::hardware::audio::core::internal
\ No newline at end of file
diff --git a/audio/aidl/default/bassboost/BassBoostSw.cpp b/audio/aidl/default/bassboost/BassBoostSw.cpp
index c52d16f..7971dee 100644
--- a/audio/aidl/default/bassboost/BassBoostSw.cpp
+++ b/audio/aidl/default/bassboost/BassBoostSw.cpp
@@ -14,10 +14,11 @@
* limitations under the License.
*/
+#include <algorithm>
#include <cstddef>
+#include <memory>
#define LOG_TAG "AHAL_BassBoostSw"
#include <Utils.h>
-#include <algorithm>
#include <unordered_set>
#include <android-base/logging.h>
@@ -73,28 +74,74 @@
ndk::ScopedAStatus BassBoostSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::bassBoost != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
- mSpecificParam = specific.get<Parameter::Specific::bassBoost>();
- LOG(DEBUG) << __func__ << " success with: " << specific.toString();
- return ndk::ScopedAStatus::ok();
+ auto& bbParam = specific.get<Parameter::Specific::bassBoost>();
+ auto tag = bbParam.getTag();
+
+ switch (tag) {
+ case BassBoost::strengthPm: {
+ RETURN_IF(!mStrengthSupported, EX_ILLEGAL_ARGUMENT, "SettingStrengthNotSupported");
+
+ RETURN_IF(mContext->setBbStrengthPm(bbParam.get<BassBoost::strengthPm>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "strengthPmNotSupported");
+ return ndk::ScopedAStatus::ok();
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "BassBoostTagNotSupported");
+ }
+ }
}
ndk::ScopedAStatus BassBoostSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::bassBoostTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
- specific->set<Parameter::Specific::bassBoost>(mSpecificParam);
+ auto bbId = id.get<Parameter::Id::bassBoostTag>();
+ auto bbIdTag = bbId.getTag();
+ switch (bbIdTag) {
+ case BassBoost::Id::commonTag:
+ return getParameterBassBoost(bbId.get<BassBoost::Id::commonTag>(), specific);
+ default:
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "BassBoostTagNotSupported");
+ }
+}
+
+ndk::ScopedAStatus BassBoostSw::getParameterBassBoost(const BassBoost::Tag& tag,
+ Parameter::Specific* specific) {
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ BassBoost bbParam;
+ switch (tag) {
+ case BassBoost::strengthPm: {
+ bbParam.set<BassBoost::strengthPm>(mContext->getBbStrengthPm());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "BassBoostTagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::bassBoost>(bbParam);
return ndk::ScopedAStatus::ok();
}
std::shared_ptr<EffectContext> BassBoostSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
- return mContext;
+ } else {
+ mContext = std::make_shared<BassBoostSwContext>(1 /* statusFmqDepth */, common);
}
- mContext = std::make_shared<BassBoostSwContext>(1 /* statusFmqDepth */, common);
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> BassBoostSw::getContext() {
return mContext;
}
@@ -106,13 +153,13 @@
}
// Processing method running in EffectWorker thread.
-IEffect::Status BassBoostSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status BassBoostSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
- for (int i = 0; i < process; i++) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- return {STATUS_OK, process, process};
+ return {STATUS_OK, samples, samples};
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/bassboost/BassBoostSw.h b/audio/aidl/default/bassboost/BassBoostSw.h
index 90a8887..24ea652 100644
--- a/audio/aidl/default/bassboost/BassBoostSw.h
+++ b/audio/aidl/default/bassboost/BassBoostSw.h
@@ -32,7 +32,21 @@
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
- // TODO: add specific context here
+
+ RetCode setBbStrengthPm(int strength) {
+ if (strength < BassBoost::MIN_PER_MILLE_STRENGTH ||
+ strength > BassBoost::MAX_PER_MILLE_STRENGTH) {
+ LOG(ERROR) << __func__ << " invalid strength: " << strength;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ // TODO : Add implementation to apply new strength
+ mStrength = strength;
+ return RetCode::SUCCESS;
+ }
+ int getBbStrengthPm() const { return mStrength; }
+
+ private:
+ int mStrength;
};
class BassBoostSw final : public EffectImpl {
@@ -47,14 +61,20 @@
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
+ std::string getEffectName() override { return kEffectName; };
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+
private:
+ const std::string kEffectName = "BassBoostSw";
std::shared_ptr<BassBoostSwContext> mContext;
/* capabilities */
- const BassBoost::Capability kCapability;
+ const bool mStrengthSupported = true;
+ const BassBoost::Capability kCapability = {.strengthSupported = mStrengthSupported};
/* Effect descriptor */
const Descriptor kDescriptor = {
.common = {.id = {.type = kBassBoostTypeUUID,
@@ -63,11 +83,11 @@
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
- .name = "BassBoostSw",
+ .name = kEffectName,
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::bassBoost>(kCapability)};
- /* parameters */
- BassBoost mSpecificParam;
+ ndk::ScopedAStatus getParameterBassBoost(const BassBoost::Tag& tag,
+ Parameter::Specific* specific);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/config/audioPolicy/Android.bp b/audio/aidl/default/config/audioPolicy/Android.bp
new file mode 100644
index 0000000..6d8a148
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/Android.bp
@@ -0,0 +1,15 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+xsd_config {
+ name: "audio_policy_configuration_aidl_default",
+ srcs: ["audio_policy_configuration.xsd"],
+ package_name: "android.audio.policy.configuration",
+ nullability: true,
+}
diff --git a/audio/aidl/default/config/audioPolicy/api/current.txt b/audio/aidl/default/config/audioPolicy/api/current.txt
new file mode 100644
index 0000000..c0ffe70
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/api/current.txt
@@ -0,0 +1,607 @@
+// Signature format: 2.0
+package android.audio.policy.configuration {
+
+ public class AttachedDevices {
+ ctor public AttachedDevices();
+ method @Nullable public java.util.List<java.lang.String> getItem();
+ }
+
+ public enum AudioChannelMask {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_1;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_10;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_11;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_12;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_13;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_14;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_15;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_16;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_17;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_18;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_19;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_20;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_21;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_22;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_23;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_24;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_3;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_4;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_5;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_6;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_7;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_8;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_INDEX_MASK_9;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_2POINT0POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_2POINT1POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_3POINT0POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_3POINT1POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_5POINT1;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_6;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_FRONT_BACK;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_MONO;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_STEREO;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_CALL_MONO;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_DNLINK_MONO;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_IN_VOICE_UPLINK_MONO;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_NONE;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_13POINT_360RA;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_22POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT0POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT1;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_2POINT1POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_3POINT0POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_3POINT1;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_3POINT1POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1POINT4;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1_BACK;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_5POINT1_SIDE;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_6POINT1;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_7POINT1;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_7POINT1POINT2;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_7POINT1POINT4;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_9POINT1POINT4;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_9POINT1POINT6;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_HAPTIC_AB;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_MONO;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_MONO_HAPTIC_A;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_MONO_HAPTIC_AB;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_PENTA;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_QUAD;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_QUAD_BACK;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_QUAD_SIDE;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_STEREO;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_STEREO_HAPTIC_A;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_STEREO_HAPTIC_AB;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_SURROUND;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_TRI;
+ enum_constant public static final android.audio.policy.configuration.AudioChannelMask AUDIO_CHANNEL_OUT_TRI_BACK;
+ }
+
+ public enum AudioContentType {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_MOVIE;
+ enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_MUSIC;
+ enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_SONIFICATION;
+ enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_SPEECH;
+ enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_ULTRASOUND;
+ enum_constant public static final android.audio.policy.configuration.AudioContentType AUDIO_CONTENT_TYPE_UNKNOWN;
+ }
+
+ public enum AudioDevice {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_AMBIENT;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_AUX_DIGITAL;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_BACK_MIC;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_BLE_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_A2DP;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_BLE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_BUILTIN_MIC;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_BUS;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_COMMUNICATION;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_DEFAULT;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_ECHO_REFERENCE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_FM_TUNER;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_HDMI;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_HDMI_ARC;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_HDMI_EARC;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_IP;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_LINE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_LOOPBACK;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_PROXY;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_SPDIF;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_STUB;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_TELEPHONY_RX;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_TV_TUNER;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_USB_ACCESSORY;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_USB_DEVICE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_USB_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_VOICE_CALL;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_IN_WIRED_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_NONE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_AUX_LINE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLE_BROADCAST;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLE_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLE_SPEAKER;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_BUS;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_DEFAULT;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_EARPIECE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_ECHO_CANCELLER;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_FM;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_HDMI;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_HDMI_ARC;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_HDMI_EARC;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_HEARING_AID;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_IP;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_LINE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_PROXY;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_SPDIF;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_SPEAKER;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_SPEAKER_SAFE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_STUB;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_TELEPHONY_TX;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_USB_DEVICE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_USB_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+ enum_constant public static final android.audio.policy.configuration.AudioDevice AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ }
+
+ public enum AudioEncapsulationType {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.AudioEncapsulationType AUDIO_ENCAPSULATION_TYPE_IEC61937;
+ enum_constant public static final android.audio.policy.configuration.AudioEncapsulationType AUDIO_ENCAPSULATION_TYPE_NONE;
+ }
+
+ public enum AudioFormat {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADIF;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_ELD;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_ERLC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V1;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_HE_V2;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_LC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_LD;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_LTP;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_MAIN;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_SCALABLE;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_SSR;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ADTS_XHE;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ELD;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_ERLC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_HE_V1;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_HE_V2;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_LATM;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V1;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_LATM_HE_V2;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_LATM_LC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_LC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_LD;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_LTP;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_MAIN;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_SCALABLE;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_SSR;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AAC_XHE;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AC3;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AC4;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_ALAC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AMR_NB;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AMR_WB;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_AMR_WB_PLUS;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_APE;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_APTX;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_APTX_ADAPTIVE;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_APTX_ADAPTIVE_QLEA;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_APTX_ADAPTIVE_R4;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_APTX_HD;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_APTX_TWSP;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_CELT;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DEFAULT;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DOLBY_TRUEHD;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DRA;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DSD;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DTS;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DTS_HD;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DTS_HD_MA;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DTS_UHD;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_DTS_UHD_P2;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_EVRC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_EVRCB;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_EVRCNW;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_EVRCWB;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_E_AC3;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_E_AC3_JOC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_FLAC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_HE_AAC_V1;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_HE_AAC_V2;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_IEC60958;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_IEC61937;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_LC3;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_LDAC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_LHDC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_LHDC_LL;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MAT;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MAT_1_0;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MAT_2_0;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MAT_2_1;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MP2;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MP3;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MPEGH_BL_L3;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MPEGH_BL_L4;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MPEGH_LC_L3;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_MPEGH_LC_L4;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_OPUS;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_PCM_16_BIT;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_PCM_24_BIT_PACKED;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_PCM_32_BIT;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_PCM_8_24_BIT;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_PCM_8_BIT;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_PCM_FLOAT;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_QCELP;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_SBC;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_VORBIS;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_WMA;
+ enum_constant public static final android.audio.policy.configuration.AudioFormat AUDIO_FORMAT_WMA_PRO;
+ }
+
+ public enum AudioGainMode {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.AudioGainMode AUDIO_GAIN_MODE_CHANNELS;
+ enum_constant public static final android.audio.policy.configuration.AudioGainMode AUDIO_GAIN_MODE_JOINT;
+ enum_constant public static final android.audio.policy.configuration.AudioGainMode AUDIO_GAIN_MODE_RAMP;
+ }
+
+ public enum AudioInOutFlag {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_DIRECT;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_FAST;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_HW_AV_SYNC;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_HW_HOTWORD;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_MMAP_NOIRQ;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_RAW;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_SYNC;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_ULTRASOUND;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_INPUT_FLAG_VOIP_TX;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_DIRECT;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_DIRECT_PCM;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_FAST;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_HW_AV_SYNC;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_INCALL_MUSIC;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_NON_BLOCKING;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_PRIMARY;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_RAW;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_SPATIALIZER;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_SYNC;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_TTS;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_ULTRASOUND;
+ enum_constant public static final android.audio.policy.configuration.AudioInOutFlag AUDIO_OUTPUT_FLAG_VOIP_RX;
+ }
+
+ public class AudioPolicyConfiguration {
+ ctor public AudioPolicyConfiguration();
+ method @Nullable public android.audio.policy.configuration.GlobalConfiguration getGlobalConfiguration();
+ method @Nullable public java.util.List<android.audio.policy.configuration.Modules> getModules();
+ method @Nullable public android.audio.policy.configuration.SurroundSound getSurroundSound();
+ method @Nullable public android.audio.policy.configuration.Version getVersion();
+ method @Nullable public java.util.List<android.audio.policy.configuration.Volumes> getVolumes();
+ method public void setGlobalConfiguration(@Nullable android.audio.policy.configuration.GlobalConfiguration);
+ method public void setSurroundSound(@Nullable android.audio.policy.configuration.SurroundSound);
+ method public void setVersion(@Nullable android.audio.policy.configuration.Version);
+ }
+
+ public enum AudioSource {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_CAMCORDER;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_DEFAULT;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_ECHO_REFERENCE;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_FM_TUNER;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_HOTWORD;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_MIC;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_REMOTE_SUBMIX;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_ULTRASOUND;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_UNPROCESSED;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_VOICE_CALL;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_VOICE_COMMUNICATION;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_VOICE_DOWNLINK;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_VOICE_PERFORMANCE;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_VOICE_RECOGNITION;
+ enum_constant public static final android.audio.policy.configuration.AudioSource AUDIO_SOURCE_VOICE_UPLINK;
+ }
+
+ public enum AudioStreamType {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_ACCESSIBILITY;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_ALARM;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_ASSISTANT;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_BLUETOOTH_SCO;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_CALL_ASSISTANT;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_DTMF;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_ENFORCED_AUDIBLE;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_MUSIC;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_NOTIFICATION;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_PATCH;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_REROUTING;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_RING;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_SYSTEM;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_TTS;
+ enum_constant public static final android.audio.policy.configuration.AudioStreamType AUDIO_STREAM_VOICE_CALL;
+ }
+
+ public enum AudioUsage {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ALARM;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ANNOUNCEMENT;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ASSISTANCE_SONIFICATION;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_ASSISTANT;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_CALL_ASSISTANT;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_EMERGENCY;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_GAME;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_MEDIA;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_NOTIFICATION;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_NOTIFICATION_EVENT;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_SAFETY;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_UNKNOWN;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_VEHICLE_STATUS;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_VIRTUAL_SOURCE;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION;
+ enum_constant public static final android.audio.policy.configuration.AudioUsage AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
+ }
+
+ public enum DeviceCategory {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.DeviceCategory DEVICE_CATEGORY_EARPIECE;
+ enum_constant public static final android.audio.policy.configuration.DeviceCategory DEVICE_CATEGORY_EXT_MEDIA;
+ enum_constant public static final android.audio.policy.configuration.DeviceCategory DEVICE_CATEGORY_HEADSET;
+ enum_constant public static final android.audio.policy.configuration.DeviceCategory DEVICE_CATEGORY_HEARING_AID;
+ enum_constant public static final android.audio.policy.configuration.DeviceCategory DEVICE_CATEGORY_SPEAKER;
+ }
+
+ public class DevicePorts {
+ ctor public DevicePorts();
+ method @Nullable public java.util.List<android.audio.policy.configuration.DevicePorts.DevicePort> getDevicePort();
+ }
+
+ public static class DevicePorts.DevicePort {
+ ctor public DevicePorts.DevicePort();
+ method @Nullable public String getAddress();
+ method @Nullable public java.util.List<java.lang.String> getEncodedFormats();
+ method @Nullable public android.audio.policy.configuration.Gains getGains();
+ method @Nullable public java.util.List<android.audio.policy.configuration.Profile> getProfile();
+ method @Nullable public android.audio.policy.configuration.Role getRole();
+ method @Nullable public String getTagName();
+ method @Nullable public String getType();
+ method @Nullable public boolean get_default();
+ method public void setAddress(@Nullable String);
+ method public void setEncodedFormats(@Nullable java.util.List<java.lang.String>);
+ method public void setGains(@Nullable android.audio.policy.configuration.Gains);
+ method public void setRole(@Nullable android.audio.policy.configuration.Role);
+ method public void setTagName(@Nullable String);
+ method public void setType(@Nullable String);
+ method public void set_default(@Nullable boolean);
+ }
+
+ public enum EngineSuffix {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.EngineSuffix _default;
+ enum_constant public static final android.audio.policy.configuration.EngineSuffix configurable;
+ }
+
+ public class Gains {
+ ctor public Gains();
+ method @Nullable public java.util.List<android.audio.policy.configuration.Gains.Gain> getGain();
+ }
+
+ public static class Gains.Gain {
+ ctor public Gains.Gain();
+ method @Nullable public android.audio.policy.configuration.AudioChannelMask getChannel_mask();
+ method @Nullable public int getDefaultValueMB();
+ method @Nullable public int getMaxRampMs();
+ method @Nullable public int getMaxValueMB();
+ method @Nullable public int getMinRampMs();
+ method @Nullable public int getMinValueMB();
+ method @Nullable public java.util.List<android.audio.policy.configuration.AudioGainMode> getMode();
+ method @Nullable public String getName();
+ method @Nullable public int getStepValueMB();
+ method @Nullable public boolean getUseForVolume();
+ method public void setChannel_mask(@Nullable android.audio.policy.configuration.AudioChannelMask);
+ method public void setDefaultValueMB(@Nullable int);
+ method public void setMaxRampMs(@Nullable int);
+ method public void setMaxValueMB(@Nullable int);
+ method public void setMinRampMs(@Nullable int);
+ method public void setMinValueMB(@Nullable int);
+ method public void setMode(@Nullable java.util.List<android.audio.policy.configuration.AudioGainMode>);
+ method public void setName(@Nullable String);
+ method public void setStepValueMB(@Nullable int);
+ method public void setUseForVolume(@Nullable boolean);
+ }
+
+ public class GlobalConfiguration {
+ ctor public GlobalConfiguration();
+ method @Nullable public boolean getCall_screen_mode_supported();
+ method @Nullable public android.audio.policy.configuration.EngineSuffix getEngine_library();
+ method @Nullable public boolean getSpeaker_drc_enabled();
+ method public void setCall_screen_mode_supported(@Nullable boolean);
+ method public void setEngine_library(@Nullable android.audio.policy.configuration.EngineSuffix);
+ method public void setSpeaker_drc_enabled(@Nullable boolean);
+ }
+
+ public enum HalVersion {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.HalVersion _2_0;
+ enum_constant public static final android.audio.policy.configuration.HalVersion _3_0;
+ }
+
+ public class MixPorts {
+ ctor public MixPorts();
+ method @Nullable public java.util.List<android.audio.policy.configuration.MixPorts.MixPort> getMixPort();
+ }
+
+ public static class MixPorts.MixPort {
+ ctor public MixPorts.MixPort();
+ method @Nullable public java.util.List<android.audio.policy.configuration.AudioInOutFlag> getFlags();
+ method @Nullable public android.audio.policy.configuration.Gains getGains();
+ method @Nullable public long getMaxActiveCount();
+ method @Nullable public long getMaxOpenCount();
+ method @Nullable public String getName();
+ method @Nullable public java.util.List<android.audio.policy.configuration.AudioUsage> getPreferredUsage();
+ method @Nullable public java.util.List<android.audio.policy.configuration.Profile> getProfile();
+ method @Nullable public long getRecommendedMuteDurationMs();
+ method @Nullable public android.audio.policy.configuration.Role getRole();
+ method public void setFlags(@Nullable java.util.List<android.audio.policy.configuration.AudioInOutFlag>);
+ method public void setGains(@Nullable android.audio.policy.configuration.Gains);
+ method public void setMaxActiveCount(@Nullable long);
+ method public void setMaxOpenCount(@Nullable long);
+ method public void setName(@Nullable String);
+ method public void setPreferredUsage(@Nullable java.util.List<android.audio.policy.configuration.AudioUsage>);
+ method public void setRecommendedMuteDurationMs(@Nullable long);
+ method public void setRole(@Nullable android.audio.policy.configuration.Role);
+ }
+
+ public enum MixType {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.MixType mix;
+ enum_constant public static final android.audio.policy.configuration.MixType mux;
+ }
+
+ public class Modules {
+ ctor public Modules();
+ method @Nullable public java.util.List<android.audio.policy.configuration.Modules.Module> getModule();
+ }
+
+ public static class Modules.Module {
+ ctor public Modules.Module();
+ method @Nullable public android.audio.policy.configuration.AttachedDevices getAttachedDevices();
+ method @Nullable public String getDefaultOutputDevice();
+ method @Nullable public android.audio.policy.configuration.DevicePorts getDevicePorts();
+ method @Nullable public android.audio.policy.configuration.HalVersion getHalVersion();
+ method @Nullable public android.audio.policy.configuration.MixPorts getMixPorts();
+ method @Nullable public String getName();
+ method @Nullable public android.audio.policy.configuration.Routes getRoutes();
+ method public void setAttachedDevices(@Nullable android.audio.policy.configuration.AttachedDevices);
+ method public void setDefaultOutputDevice(@Nullable String);
+ method public void setDevicePorts(@Nullable android.audio.policy.configuration.DevicePorts);
+ method public void setHalVersion(@Nullable android.audio.policy.configuration.HalVersion);
+ method public void setMixPorts(@Nullable android.audio.policy.configuration.MixPorts);
+ method public void setName(@Nullable String);
+ method public void setRoutes(@Nullable android.audio.policy.configuration.Routes);
+ }
+
+ public class Profile {
+ ctor public Profile();
+ method @Nullable public java.util.List<android.audio.policy.configuration.AudioChannelMask> getChannelMasks();
+ method @Nullable public android.audio.policy.configuration.AudioEncapsulationType getEncapsulationType();
+ method @Nullable public String getFormat();
+ method @Nullable public String getName();
+ method @Nullable public java.util.List<java.math.BigInteger> getSamplingRates();
+ method public void setChannelMasks(@Nullable java.util.List<android.audio.policy.configuration.AudioChannelMask>);
+ method public void setEncapsulationType(@Nullable android.audio.policy.configuration.AudioEncapsulationType);
+ method public void setFormat(@Nullable String);
+ method public void setName(@Nullable String);
+ method public void setSamplingRates(@Nullable java.util.List<java.math.BigInteger>);
+ }
+
+ public class Reference {
+ ctor public Reference();
+ method @Nullable public String getName();
+ method @Nullable public java.util.List<java.lang.String> getPoint();
+ method public void setName(@Nullable String);
+ }
+
+ public enum Role {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.Role sink;
+ enum_constant public static final android.audio.policy.configuration.Role source;
+ }
+
+ public class Routes {
+ ctor public Routes();
+ method @Nullable public java.util.List<android.audio.policy.configuration.Routes.Route> getRoute();
+ }
+
+ public static class Routes.Route {
+ ctor public Routes.Route();
+ method @Nullable public String getSink();
+ method @Nullable public String getSources();
+ method @Nullable public android.audio.policy.configuration.MixType getType();
+ method public void setSink(@Nullable String);
+ method public void setSources(@Nullable String);
+ method public void setType(@Nullable android.audio.policy.configuration.MixType);
+ }
+
+ public class SurroundFormats {
+ ctor public SurroundFormats();
+ method @Nullable public java.util.List<android.audio.policy.configuration.SurroundFormats.Format> getFormat();
+ }
+
+ public static class SurroundFormats.Format {
+ ctor public SurroundFormats.Format();
+ method @Nullable public String getName();
+ method @Nullable public java.util.List<java.lang.String> getSubformats();
+ method public void setName(@Nullable String);
+ method public void setSubformats(@Nullable java.util.List<java.lang.String>);
+ }
+
+ public class SurroundSound {
+ ctor public SurroundSound();
+ method @Nullable public android.audio.policy.configuration.SurroundFormats getFormats();
+ method public void setFormats(@Nullable android.audio.policy.configuration.SurroundFormats);
+ }
+
+ public enum Version {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.configuration.Version _7_0;
+ enum_constant public static final android.audio.policy.configuration.Version _7_1;
+ }
+
+ public class Volume {
+ ctor public Volume();
+ method @Nullable public android.audio.policy.configuration.DeviceCategory getDeviceCategory();
+ method @Nullable public java.util.List<java.lang.String> getPoint();
+ method @Nullable public String getRef();
+ method @Nullable public android.audio.policy.configuration.AudioStreamType getStream();
+ method public void setDeviceCategory(@Nullable android.audio.policy.configuration.DeviceCategory);
+ method public void setRef(@Nullable String);
+ method public void setStream(@Nullable android.audio.policy.configuration.AudioStreamType);
+ }
+
+ public class Volumes {
+ ctor public Volumes();
+ method @Nullable public java.util.List<android.audio.policy.configuration.Reference> getReference();
+ method @Nullable public java.util.List<android.audio.policy.configuration.Volume> getVolume();
+ }
+
+ public class XmlParser {
+ ctor public XmlParser();
+ method @Nullable public static android.audio.policy.configuration.AudioPolicyConfiguration read(@NonNull java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method @Nullable public static String readText(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static void skip(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ }
+
+}
+
diff --git a/audio/aidl/default/config/audioPolicy/api/last_current.txt b/audio/aidl/default/config/audioPolicy/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/api/last_current.txt
diff --git a/audio/aidl/default/config/audioPolicy/api/last_removed.txt b/audio/aidl/default/config/audioPolicy/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/api/last_removed.txt
diff --git a/audio/aidl/default/config/audioPolicy/api/removed.txt b/audio/aidl/default/config/audioPolicy/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/audio/aidl/default/config/audio_policy_configuration.xsd b/audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
similarity index 100%
rename from audio/aidl/default/config/audio_policy_configuration.xsd
rename to audio/aidl/default/config/audioPolicy/audio_policy_configuration.xsd
diff --git a/audio/aidl/default/config/audioPolicy/engine/Android.bp b/audio/aidl/default/config/audioPolicy/engine/Android.bp
new file mode 100644
index 0000000..b2a7310
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/engine/Android.bp
@@ -0,0 +1,15 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "hardware_interfaces_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+xsd_config {
+ name: "audio_policy_engine_configuration_aidl_default",
+ srcs: ["audio_policy_engine_configuration.xsd"],
+ package_name: "android.audio.policy.engine.configuration",
+ nullability: true,
+}
diff --git a/audio/aidl/default/config/audioPolicy/engine/api/current.txt b/audio/aidl/default/config/audioPolicy/engine/api/current.txt
new file mode 100644
index 0000000..59574f3
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/engine/api/current.txt
@@ -0,0 +1,302 @@
+// Signature format: 2.0
+package android.audio.policy.engine.configuration {
+
+ public class AttributesGroup {
+ ctor public AttributesGroup();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.AttributesType> getAttributes_optional();
+ method @Nullable public android.audio.policy.engine.configuration.BundleType getBundle_optional();
+ method @Nullable public android.audio.policy.engine.configuration.ContentTypeType getContentType_optional();
+ method @Nullable public android.audio.policy.engine.configuration.FlagsType getFlags_optional();
+ method @Nullable public android.audio.policy.engine.configuration.SourceType getSource_optional();
+ method @Nullable public android.audio.policy.engine.configuration.Stream getStreamType();
+ method @Nullable public android.audio.policy.engine.configuration.UsageType getUsage_optional();
+ method @Nullable public String getVolumeGroup();
+ method public void setBundle_optional(@Nullable android.audio.policy.engine.configuration.BundleType);
+ method public void setContentType_optional(@Nullable android.audio.policy.engine.configuration.ContentTypeType);
+ method public void setFlags_optional(@Nullable android.audio.policy.engine.configuration.FlagsType);
+ method public void setSource_optional(@Nullable android.audio.policy.engine.configuration.SourceType);
+ method public void setStreamType(@Nullable android.audio.policy.engine.configuration.Stream);
+ method public void setUsage_optional(@Nullable android.audio.policy.engine.configuration.UsageType);
+ method public void setVolumeGroup(@Nullable String);
+ }
+
+ public class AttributesRef {
+ ctor public AttributesRef();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.AttributesRefType> getReference();
+ }
+
+ public class AttributesRefType {
+ ctor public AttributesRefType();
+ method @Nullable public android.audio.policy.engine.configuration.AttributesType getAttributes();
+ method @Nullable public String getName();
+ method public void setAttributes(@Nullable android.audio.policy.engine.configuration.AttributesType);
+ method public void setName(@Nullable String);
+ }
+
+ public class AttributesType {
+ ctor public AttributesType();
+ method @Nullable public String getAttributesRef();
+ method @Nullable public android.audio.policy.engine.configuration.BundleType getBundle();
+ method @Nullable public android.audio.policy.engine.configuration.ContentTypeType getContentType();
+ method @Nullable public android.audio.policy.engine.configuration.FlagsType getFlags();
+ method @Nullable public android.audio.policy.engine.configuration.SourceType getSource();
+ method @Nullable public android.audio.policy.engine.configuration.UsageType getUsage();
+ method public void setAttributesRef(@Nullable String);
+ method public void setBundle(@Nullable android.audio.policy.engine.configuration.BundleType);
+ method public void setContentType(@Nullable android.audio.policy.engine.configuration.ContentTypeType);
+ method public void setFlags(@Nullable android.audio.policy.engine.configuration.FlagsType);
+ method public void setSource(@Nullable android.audio.policy.engine.configuration.SourceType);
+ method public void setUsage(@Nullable android.audio.policy.engine.configuration.UsageType);
+ }
+
+ public class BundleType {
+ ctor public BundleType();
+ method @Nullable public String getKey();
+ method @Nullable public String getValue();
+ method public void setKey(@Nullable String);
+ method public void setValue(@Nullable String);
+ }
+
+ public class Configuration {
+ ctor public Configuration();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.AttributesRef> getAttributesRef();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.CriteriaType> getCriteria();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.CriterionTypesType> getCriterion_types();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.ProductStrategies> getProductStrategies();
+ method @Nullable public android.audio.policy.engine.configuration.Version getVersion();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.VolumeGroupsType> getVolumeGroups();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.VolumesType> getVolumes();
+ method public void setVersion(@Nullable android.audio.policy.engine.configuration.Version);
+ }
+
+ public enum ContentType {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.engine.configuration.ContentType AUDIO_CONTENT_TYPE_MOVIE;
+ enum_constant public static final android.audio.policy.engine.configuration.ContentType AUDIO_CONTENT_TYPE_MUSIC;
+ enum_constant public static final android.audio.policy.engine.configuration.ContentType AUDIO_CONTENT_TYPE_SONIFICATION;
+ enum_constant public static final android.audio.policy.engine.configuration.ContentType AUDIO_CONTENT_TYPE_SPEECH;
+ enum_constant public static final android.audio.policy.engine.configuration.ContentType AUDIO_CONTENT_TYPE_UNKNOWN;
+ }
+
+ public class ContentTypeType {
+ ctor public ContentTypeType();
+ method @Nullable public android.audio.policy.engine.configuration.ContentType getValue();
+ method public void setValue(@Nullable android.audio.policy.engine.configuration.ContentType);
+ }
+
+ public class CriteriaType {
+ ctor public CriteriaType();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.CriterionType> getCriterion();
+ }
+
+ public class CriterionType {
+ ctor public CriterionType();
+ method @Nullable public String getName();
+ method @Nullable public String getType();
+ method @Nullable public String get_default();
+ method public void setName(@Nullable String);
+ method public void setType(@Nullable String);
+ method public void set_default(@Nullable String);
+ }
+
+ public class CriterionTypeType {
+ ctor public CriterionTypeType();
+ method @Nullable public String getName();
+ method @Nullable public android.audio.policy.engine.configuration.PfwCriterionTypeEnum getType();
+ method @Nullable public android.audio.policy.engine.configuration.ValuesType getValues();
+ method public void setName(@Nullable String);
+ method public void setType(@Nullable android.audio.policy.engine.configuration.PfwCriterionTypeEnum);
+ method public void setValues(@Nullable android.audio.policy.engine.configuration.ValuesType);
+ }
+
+ public class CriterionTypesType {
+ ctor public CriterionTypesType();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.CriterionTypeType> getCriterion_type();
+ }
+
+ public enum DeviceCategory {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.engine.configuration.DeviceCategory DEVICE_CATEGORY_EARPIECE;
+ enum_constant public static final android.audio.policy.engine.configuration.DeviceCategory DEVICE_CATEGORY_EXT_MEDIA;
+ enum_constant public static final android.audio.policy.engine.configuration.DeviceCategory DEVICE_CATEGORY_HEADSET;
+ enum_constant public static final android.audio.policy.engine.configuration.DeviceCategory DEVICE_CATEGORY_HEARING_AID;
+ enum_constant public static final android.audio.policy.engine.configuration.DeviceCategory DEVICE_CATEGORY_SPEAKER;
+ }
+
+ public enum FlagType {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_AUDIBILITY_ENFORCED;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_BEACON;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_BYPASS_MUTE;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_CAPTURE_PRIVATE;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_DEEP_BUFFER;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_HW_AV_SYNC;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_HW_HOTWORD;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_LOW_LATENCY;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_MUTE_HAPTIC;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_NONE;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_NO_MEDIA_PROJECTION;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_NO_SYSTEM_CAPTURE;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_SCO;
+ enum_constant public static final android.audio.policy.engine.configuration.FlagType AUDIO_FLAG_SECURE;
+ }
+
+ public class FlagsType {
+ ctor public FlagsType();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.FlagType> getValue();
+ method public void setValue(@Nullable java.util.List<android.audio.policy.engine.configuration.FlagType>);
+ }
+
+ public enum PfwCriterionTypeEnum {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.engine.configuration.PfwCriterionTypeEnum exclusive;
+ enum_constant public static final android.audio.policy.engine.configuration.PfwCriterionTypeEnum inclusive;
+ }
+
+ public class ProductStrategies {
+ ctor public ProductStrategies();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.ProductStrategies.ProductStrategy> getProductStrategy();
+ }
+
+ public static class ProductStrategies.ProductStrategy {
+ ctor public ProductStrategies.ProductStrategy();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.AttributesGroup> getAttributesGroup();
+ method @Nullable public String getName();
+ method public void setName(@Nullable String);
+ }
+
+ public enum SourceEnumType {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_CAMCORDER;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_DEFAULT;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_ECHO_REFERENCE;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_FM_TUNER;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_MIC;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_REMOTE_SUBMIX;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_UNPROCESSED;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_VOICE_CALL;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_VOICE_COMMUNICATION;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_VOICE_DOWNLINK;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_VOICE_PERFORMANCE;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_VOICE_RECOGNITION;
+ enum_constant public static final android.audio.policy.engine.configuration.SourceEnumType AUDIO_SOURCE_VOICE_UPLINK;
+ }
+
+ public class SourceType {
+ ctor public SourceType();
+ method @Nullable public android.audio.policy.engine.configuration.SourceEnumType getValue();
+ method public void setValue(@Nullable android.audio.policy.engine.configuration.SourceEnumType);
+ }
+
+ public enum Stream {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_ACCESSIBILITY;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_ALARM;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_ASSISTANT;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_BLUETOOTH_SCO;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_DEFAULT;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_DTMF;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_ENFORCED_AUDIBLE;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_MUSIC;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_NOTIFICATION;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_RING;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_SYSTEM;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_TTS;
+ enum_constant public static final android.audio.policy.engine.configuration.Stream AUDIO_STREAM_VOICE_CALL;
+ }
+
+ public enum UsageEnumType {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ALARM;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANCE_SONIFICATION;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_ASSISTANT;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_CALL_ASSISTANT;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_GAME;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_MEDIA;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_EVENT;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_UNKNOWN;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VIRTUAL_SOURCE;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION;
+ enum_constant public static final android.audio.policy.engine.configuration.UsageEnumType AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
+ }
+
+ public class UsageType {
+ ctor public UsageType();
+ method @Nullable public android.audio.policy.engine.configuration.UsageEnumType getValue();
+ method public void setValue(@Nullable android.audio.policy.engine.configuration.UsageEnumType);
+ }
+
+ public class ValueType {
+ ctor public ValueType();
+ method @Nullable public String getAndroid_type();
+ method @Nullable public String getLiteral();
+ method @Nullable public long getNumerical();
+ method public void setAndroid_type(@Nullable String);
+ method public void setLiteral(@Nullable String);
+ method public void setNumerical(@Nullable long);
+ }
+
+ public class ValuesType {
+ ctor public ValuesType();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.ValueType> getValue();
+ }
+
+ public enum Version {
+ method @NonNull public String getRawName();
+ enum_constant public static final android.audio.policy.engine.configuration.Version _1_0;
+ }
+
+ public class Volume {
+ ctor public Volume();
+ method @Nullable public android.audio.policy.engine.configuration.DeviceCategory getDeviceCategory();
+ method @Nullable public java.util.List<java.lang.String> getPoint();
+ method @Nullable public String getRef();
+ method public void setDeviceCategory(@Nullable android.audio.policy.engine.configuration.DeviceCategory);
+ method public void setRef(@Nullable String);
+ }
+
+ public class VolumeGroupsType {
+ ctor public VolumeGroupsType();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.VolumeGroupsType.VolumeGroup> getVolumeGroup();
+ }
+
+ public static class VolumeGroupsType.VolumeGroup {
+ ctor public VolumeGroupsType.VolumeGroup();
+ method @Nullable public int getIndexMax();
+ method @Nullable public int getIndexMin();
+ method @Nullable public String getName();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.Volume> getVolume();
+ method public void setIndexMax(@Nullable int);
+ method public void setIndexMin(@Nullable int);
+ method public void setName(@Nullable String);
+ }
+
+ public class VolumeRef {
+ ctor public VolumeRef();
+ method @Nullable public String getName();
+ method @Nullable public java.util.List<java.lang.String> getPoint();
+ method public void setName(@Nullable String);
+ }
+
+ public class VolumesType {
+ ctor public VolumesType();
+ method @Nullable public java.util.List<android.audio.policy.engine.configuration.VolumeRef> getReference();
+ }
+
+ public class XmlParser {
+ ctor public XmlParser();
+ method @Nullable public static android.audio.policy.engine.configuration.Configuration read(@NonNull java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method @Nullable public static String readText(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static void skip(@NonNull org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ }
+
+}
+
diff --git a/audio/aidl/default/config/audioPolicy/engine/api/last_current.txt b/audio/aidl/default/config/audioPolicy/engine/api/last_current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/engine/api/last_current.txt
diff --git a/audio/aidl/default/config/audioPolicy/engine/api/last_removed.txt b/audio/aidl/default/config/audioPolicy/engine/api/last_removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/engine/api/last_removed.txt
diff --git a/audio/aidl/default/config/audioPolicy/engine/api/removed.txt b/audio/aidl/default/config/audioPolicy/engine/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/engine/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd b/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
new file mode 100644
index 0000000..b58a6c8
--- /dev/null
+++ b/audio/aidl/default/config/audioPolicy/engine/audio_policy_engine_configuration.xsd
@@ -0,0 +1,418 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright (C) 2019 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.
+ -->
+
+ <xs:schema version="2.0"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified"
+ xmlns:xs="http://www.w3.org/2001/XMLSchema">
+ <!-- List the config versions supported by audio policy engine. -->
+ <xs:simpleType name="version">
+ <xs:restriction base="xs:decimal">
+ <xs:enumeration value="1.0"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:element name="configuration">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="ProductStrategies" type="ProductStrategies" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="criterion_types" type="criterionTypesType" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="criteria" type="criteriaType" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="volumeGroups" type="volumeGroupsType" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="volumes" type="volumesType" minOccurs="0" maxOccurs="unbounded"/>
+ <xs:element name="attributesRef" type="attributesRef" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="version" type="version" use="required"/>
+ </xs:complexType>
+
+ <xs:key name="volumeCurveNameKey">
+ <xs:selector xpath="volumes/reference"/>
+ <xs:field xpath="@name"/>
+ </xs:key>
+ <xs:keyref name="volumeCurveRef" refer="volumeCurveNameKey">
+ <xs:selector xpath="volumeGroups/volumeGroup"/>
+ <xs:field xpath="@ref"/>
+ </xs:keyref>
+
+ <xs:key name="attributesRefNameKey">
+ <xs:selector xpath="attributesRef/reference"/>
+ <xs:field xpath="@name"/>
+ </xs:key>
+ <xs:keyref name="volumeGroupAttributesRef" refer="attributesRefNameKey">
+ <xs:selector xpath="volumeGroups/volumeGroup/volume"/>
+ <xs:field xpath="@attributesRef"/>
+ </xs:keyref>
+ <xs:keyref name="ProductStrategyAttributesRef" refer="attributesRefNameKey">
+ <xs:selector xpath="ProductStrategies/ProductStrategy/Attributes"/>
+ <xs:field xpath="@attributesRef"/>
+ </xs:keyref>
+
+ <xs:unique name="productStrategyNameUniqueness">
+ <xs:selector xpath="ProductStrategies/ProductStrategy"/>
+ <xs:field xpath="@name"/>
+ </xs:unique>
+
+ <!-- ensure validity of volume group referred in product strategy-->
+ <xs:key name="volumeGroupKey">
+ <xs:selector xpath="volumeGroups/volumeGroup/name"/>
+ <xs:field xpath="."/>
+ </xs:key>
+ <xs:keyref name="volumeGroupRef" refer="volumeGroupKey">
+ <xs:selector xpath="ProductStrategies/ProductStrategy/AttributesGroup"/>
+ <xs:field xpath="@volumeGroup"/>
+ </xs:keyref>
+
+ <xs:unique name="volumeTargetUniqueness">
+ <xs:selector xpath="volumeGroups/volumeGroup"/>
+ <xs:field xpath="@name"/>
+ <xs:field xpath="@deviceCategory"/>
+ </xs:unique>
+
+ <!-- ensure validity of criterion type referred in criterion-->
+ <xs:key name="criterionTypeKey">
+ <xs:selector xpath="criterion_types/criterion_type"/>
+ <xs:field xpath="@name"/>
+ </xs:key>
+ <xs:keyref name="criterionTypeKeyRef" refer="criterionTypeKey">
+ <xs:selector xpath="criteria/criterion"/>
+ <xs:field xpath="@type"/>
+ </xs:keyref>
+
+ </xs:element>
+
+ <xs:complexType name="ProductStrategies">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="ProductStrategy" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="AttributesGroup" type="AttributesGroup" minOccurs="1" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ </xs:complexType>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="AttributesGroup">
+ <xs:sequence>
+ <xs:choice minOccurs="0">
+ <xs:element name="Attributes" type="AttributesType" minOccurs="1" maxOccurs="unbounded"/>
+ <xs:sequence>
+ <xs:element name="ContentType" type="ContentTypeType" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="Usage" type="UsageType" minOccurs="1" maxOccurs="1"/>
+ <xs:element name="Source" type="SourceType" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="Flags" type="FlagsType" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="Bundle" type="BundleType" minOccurs="0" maxOccurs="1"/>
+ </xs:sequence>
+ </xs:choice>
+ </xs:sequence>
+ <xs:attribute name="streamType" type="stream" use="optional"/>
+ <xs:attribute name="volumeGroup" type="xs:string" use="optional"/>
+ </xs:complexType>
+
+ <xs:complexType name="volumeGroupsType">
+ <xs:sequence>
+ <xs:element name="volumeGroup" minOccurs="0" maxOccurs="unbounded">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="name" type="xs:token"/>
+ <xs:element name="indexMin" type="xs:int" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="indexMax" type="xs:int" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="volume" type="volume" minOccurs="1" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:unique name="volumeAttributesUniqueness">
+ <xs:selector xpath="volume"/>
+ <xs:field xpath="deviceCategory"/>
+ </xs:unique>
+ </xs:element>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="volumesType">
+ <xs:sequence>
+ <xs:element name="reference" type="volumeRef" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="attributesRef">
+ <xs:sequence>
+ <xs:element name="reference" type="attributesRefType" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+
+ <xs:complexType name="criteriaType">
+ <xs:sequence>
+ <xs:element name="criterion" type="criterionType" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="criterionType">
+ <xs:attribute name="name" type="xs:string" use="required"/>
+ <xs:attribute name="type" type="xs:string" use="required"/>
+ <xs:attribute name="default" type="xs:string" use="optional"/>
+ </xs:complexType>
+
+ <xs:complexType name="criterionTypesType">
+ <xs:sequence>
+ <xs:element name="criterion_type" type="criterionTypeType" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="criterionTypeType">
+ <xs:sequence>
+ <xs:element name="values" type="valuesType" minOccurs="0" maxOccurs="1"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:token" use="required"/>
+ <xs:attribute name="type" type="pfwCriterionTypeEnum" use="required"/>
+ </xs:complexType>
+
+ <xs:complexType name="valuesType">
+ <xs:sequence>
+ <xs:element name="value" type="valueType" maxOccurs="unbounded"/>
+ </xs:sequence>
+ </xs:complexType>
+ <xs:complexType name="valueType">
+ <xs:attribute name="literal" type="xs:string" use="required"/>
+ <xs:attribute name="numerical" type="xs:long" use="required"/>
+ <xs:attribute name="android_type" type="longDecimalOrHexType" use="optional"/>
+ </xs:complexType>
+
+ <xs:simpleType name="longDecimalOrHexType">
+ <xs:union memberTypes="xs:long longHexType" />
+ </xs:simpleType>
+
+ <xs:simpleType name="longHexType">
+ <xs:restriction base="xs:string">
+ <xs:pattern value="0x[0-9A-Fa-f]{1,16}"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:complexType name="attributesRefType">
+ <xs:sequence>
+ <xs:element name="Attributes" type="AttributesType" minOccurs="1" maxOccurs="1"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:token" use="required"/>
+ </xs:complexType>
+
+ <xs:complexType name="AttributesType">
+ <xs:sequence>
+ <xs:element name="ContentType" type="ContentTypeType" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="Usage" type="UsageType" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="Source" type="SourceType" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="Flags" type="FlagsType" minOccurs="0" maxOccurs="1"/>
+ <xs:element name="Bundle" type="BundleType" minOccurs="0" maxOccurs="1"/>
+ </xs:sequence>
+ <xs:attribute name="attributesRef" type="xs:token" use="optional"/>
+ <!-- with xsd 1.1, it is impossible to make choice on either attributes or element...-->
+ </xs:complexType>
+
+ <xs:complexType name="ContentTypeType">
+ <xs:attribute name="value" type="contentType" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="UsageType">
+ <xs:attribute name="value" type="usageEnumType" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="SourceType">
+ <xs:attribute name="value" type="sourceEnumType" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="FlagsType">
+ <xs:attribute name="value" type="flagsEnumType" use="required"/>
+ </xs:complexType>
+ <xs:complexType name="BundleType">
+ <xs:attribute name="key" type="xs:string" use="required"/>
+ <xs:attribute name="value" type="xs:string" use="required"/>
+ </xs:complexType>
+
+ <xs:complexType name="volume">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Volume section defines a volume curve for a given use case and device category.
+ It contains a list of points of this curve expressing the attenuation in Millibels
+ for a given volume index from 0 to 100.
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-9600</point>
+ <point>100,0</point>
+ </volume>
+
+ It may also reference a reference/@name to avoid duplicating curves.
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <reference name="DEFAULT_MEDIA_VOLUME_CURVE">
+ <point>0,-9600</point>
+ <point>100,0</point>
+ </reference>
+ </xs:documentation>
+ </xs:annotation>
+ <xs:sequence>
+ <xs:element name="point" type="volumePoint" minOccurs="0" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="deviceCategory" type="deviceCategory"/>
+ <xs:attribute name="ref" type="xs:token" use="optional"/>
+ </xs:complexType>
+
+ <xs:complexType name="volumeRef">
+ <xs:sequence>
+ <xs:element name="point" type="volumePoint" minOccurs="2" maxOccurs="unbounded"/>
+ </xs:sequence>
+ <xs:attribute name="name" type="xs:token" use="required"/>
+ </xs:complexType>
+
+ <xs:simpleType name="volumePoint">
+ <xs:annotation>
+ <xs:documentation xml:lang="en">
+ Comma separated pair of number.
+ The fist one is the framework level (between 0 and 100).
+ The second one is the volume to send to the HAL.
+ The framework will interpolate volumes not specified.
+ Their MUST be at least 2 points specified.
+ </xs:documentation>
+ </xs:annotation>
+ <xs:restriction base="xs:string">
+ <xs:pattern value="([0-9]{1,2}|100),-?[0-9]+"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+
+ <xs:simpleType name="streamsCsv">
+ <xs:list>
+ <xs:simpleType>
+ <xs:restriction base="stream">
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:list>
+ </xs:simpleType>
+
+ <!-- Enum values of audio_stream_type_t in audio-base.h
+ TODO: avoid manual sync. -->
+ <xs:simpleType name="stream">
+ <xs:restriction base="xs:NMTOKEN">
+ <!--xs:pattern value="\c+(,\c+)*"/-->
+ <xs:enumeration value="AUDIO_STREAM_DEFAULT"/>
+ <xs:enumeration value="AUDIO_STREAM_VOICE_CALL"/>
+ <xs:enumeration value="AUDIO_STREAM_SYSTEM"/>
+ <xs:enumeration value="AUDIO_STREAM_RING"/>
+ <xs:enumeration value="AUDIO_STREAM_MUSIC"/>
+ <xs:enumeration value="AUDIO_STREAM_ALARM"/>
+ <xs:enumeration value="AUDIO_STREAM_NOTIFICATION"/>
+ <xs:enumeration value="AUDIO_STREAM_BLUETOOTH_SCO"/>
+ <xs:enumeration value="AUDIO_STREAM_ENFORCED_AUDIBLE"/>
+ <xs:enumeration value="AUDIO_STREAM_DTMF"/>
+ <xs:enumeration value="AUDIO_STREAM_TTS"/>
+ <xs:enumeration value="AUDIO_STREAM_ACCESSIBILITY"/>
+ <xs:enumeration value="AUDIO_STREAM_ASSISTANT"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:simpleType name="deviceCategory">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="DEVICE_CATEGORY_HEADSET"/>
+ <xs:enumeration value="DEVICE_CATEGORY_SPEAKER"/>
+ <xs:enumeration value="DEVICE_CATEGORY_EARPIECE"/>
+ <xs:enumeration value="DEVICE_CATEGORY_EXT_MEDIA"/>
+ <xs:enumeration value="DEVICE_CATEGORY_HEARING_AID"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:simpleType name="contentType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_UNKNOWN"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_SPEECH"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_MUSIC"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_MOVIE"/>
+ <xs:enumeration value="AUDIO_CONTENT_TYPE_SONIFICATION"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:simpleType name="usageEnumType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_USAGE_UNKNOWN"/>
+ <xs:enumeration value="AUDIO_USAGE_MEDIA"/>
+ <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION"/>
+ <xs:enumeration value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING"/>
+ <xs:enumeration value="AUDIO_USAGE_ALARM"/>
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION"/>
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE"/>
+ <!-- Note: the following 3 values were deprecated in Android T (13) SDK -->
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST"/>
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT"/>
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED"/>
+ <xs:enumeration value="AUDIO_USAGE_NOTIFICATION_EVENT"/>
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY"/>
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/>
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANCE_SONIFICATION"/>
+ <xs:enumeration value="AUDIO_USAGE_GAME"/>
+ <xs:enumeration value="AUDIO_USAGE_VIRTUAL_SOURCE"/>
+ <xs:enumeration value="AUDIO_USAGE_ASSISTANT"/>
+ <xs:enumeration value="AUDIO_USAGE_CALL_ASSISTANT"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:simpleType name="flagsEnumType">
+ <xs:list>
+ <xs:simpleType>
+ <xs:restriction base="flagType">
+ </xs:restriction>
+ </xs:simpleType>
+ </xs:list>
+ </xs:simpleType>
+
+ <xs:simpleType name="flagType">
+ <xs:restriction base="xs:NMTOKEN">
+ <xs:enumeration value="AUDIO_FLAG_NONE"/>
+ <xs:enumeration value="AUDIO_FLAG_AUDIBILITY_ENFORCED"/>
+ <xs:enumeration value="AUDIO_FLAG_SECURE"/>
+ <xs:enumeration value="AUDIO_FLAG_SCO"/>
+ <xs:enumeration value="AUDIO_FLAG_BEACON"/>
+ <xs:enumeration value="AUDIO_FLAG_HW_AV_SYNC"/>
+ <xs:enumeration value="AUDIO_FLAG_HW_HOTWORD"/>
+ <xs:enumeration value="AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY"/>
+ <xs:enumeration value="AUDIO_FLAG_BYPASS_MUTE"/>
+ <xs:enumeration value="AUDIO_FLAG_LOW_LATENCY"/>
+ <xs:enumeration value="AUDIO_FLAG_DEEP_BUFFER"/>
+ <xs:enumeration value="AUDIO_FLAG_NO_MEDIA_PROJECTION"/>
+ <xs:enumeration value="AUDIO_FLAG_MUTE_HAPTIC"/>
+ <xs:enumeration value="AUDIO_FLAG_NO_SYSTEM_CAPTURE"/>
+ <xs:enumeration value="AUDIO_FLAG_CAPTURE_PRIVATE"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:simpleType name="sourceEnumType">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="AUDIO_SOURCE_DEFAULT"/>
+ <xs:enumeration value="AUDIO_SOURCE_MIC"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_UPLINK"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_DOWNLINK"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_CALL"/>
+ <xs:enumeration value="AUDIO_SOURCE_CAMCORDER"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_RECOGNITION"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_COMMUNICATION"/>
+ <xs:enumeration value="AUDIO_SOURCE_REMOTE_SUBMIX"/>
+ <xs:enumeration value="AUDIO_SOURCE_UNPROCESSED"/>
+ <xs:enumeration value="AUDIO_SOURCE_VOICE_PERFORMANCE"/>
+ <xs:enumeration value="AUDIO_SOURCE_ECHO_REFERENCE"/>
+ <xs:enumeration value="AUDIO_SOURCE_FM_TUNER"/>
+ </xs:restriction>
+ </xs:simpleType>
+
+ <xs:simpleType name="pfwCriterionTypeEnum">
+ <xs:restriction base="xs:string">
+ <xs:enumeration value="inclusive"/>
+ <xs:enumeration value="exclusive"/>
+ </xs:restriction>
+ </xs:simpleType>
+</xs:schema>
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
index 3920a58..4efd0a5 100644
--- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
@@ -73,8 +73,6 @@
ndk::ScopedAStatus DynamicsProcessingSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::dynamicsProcessing != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- std::lock_guard lg(mMutex);
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
mSpecificParam = specific.get<Parameter::Specific::dynamicsProcessing>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
@@ -93,9 +91,13 @@
const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
- return mContext;
+ } else {
+ mContext = std::make_shared<DynamicsProcessingSwContext>(1 /* statusFmqDepth */, common);
}
- mContext = std::make_shared<DynamicsProcessingSwContext>(1 /* statusFmqDepth */, common);
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> DynamicsProcessingSw::getContext() {
return mContext;
}
@@ -107,13 +109,13 @@
}
// Processing method running in EffectWorker thread.
-IEffect::Status DynamicsProcessingSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status DynamicsProcessingSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
- for (int i = 0; i < process; i++) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- return {STATUS_OK, process, process};
+ return {STATUS_OK, samples, samples};
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
index 2bc2762..3ad4f77 100644
--- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
@@ -47,11 +47,16 @@
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ std::string getEffectName() override { return kEffectName; };
+
private:
+ const std::string kEffectName = "DynamicsProcessingSw";
std::shared_ptr<DynamicsProcessingSwContext> mContext;
/* capabilities */
const DynamicsProcessing::Capability kCapability;
@@ -63,7 +68,7 @@
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
- .name = "DynamicsProcessingSw",
+ .name = kEffectName,
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::dynamicsProcessing>(kCapability)};
diff --git a/audio/aidl/default/envReverb/EnvReverbSw.cpp b/audio/aidl/default/envReverb/EnvReverbSw.cpp
index ad447ab..cb09293 100644
--- a/audio/aidl/default/envReverb/EnvReverbSw.cpp
+++ b/audio/aidl/default/envReverb/EnvReverbSw.cpp
@@ -73,8 +73,6 @@
ndk::ScopedAStatus EnvReverbSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::reverb != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- std::lock_guard lg(mMutex);
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
mSpecificParam = specific.get<Parameter::Specific::reverb>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
@@ -92,9 +90,14 @@
std::shared_ptr<EffectContext> EnvReverbSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
- return mContext;
+ } else {
+ mContext = std::make_shared<EnvReverbSwContext>(1 /* statusFmqDepth */, common);
}
- mContext = std::make_shared<EnvReverbSwContext>(1 /* statusFmqDepth */, common);
+
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> EnvReverbSw::getContext() {
return mContext;
}
@@ -106,13 +109,13 @@
}
// Processing method running in EffectWorker thread.
-IEffect::Status EnvReverbSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status EnvReverbSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
- for (int i = 0; i < process; i++) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- return {STATUS_OK, process, process};
+ return {STATUS_OK, samples, samples};
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/envReverb/EnvReverbSw.h b/audio/aidl/default/envReverb/EnvReverbSw.h
index 5a9ab27..e8629a2 100644
--- a/audio/aidl/default/envReverb/EnvReverbSw.h
+++ b/audio/aidl/default/envReverb/EnvReverbSw.h
@@ -47,11 +47,16 @@
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ std::string getEffectName() override { return kEffectName; }
+
private:
+ const std::string kEffectName = "EnvReverbSw";
std::shared_ptr<EnvReverbSwContext> mContext;
/* capabilities */
const Reverb::Capability kCapability;
@@ -63,7 +68,7 @@
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
- .name = "EnvReverbSw",
+ .name = kEffectName,
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::reverb>(kCapability)};
diff --git a/audio/aidl/default/equalizer/EqualizerSw.cpp b/audio/aidl/default/equalizer/EqualizerSw.cpp
index d61ef97..243b061 100644
--- a/audio/aidl/default/equalizer/EqualizerSw.cpp
+++ b/audio/aidl/default/equalizer/EqualizerSw.cpp
@@ -70,7 +70,6 @@
ndk::ScopedAStatus EqualizerSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::equalizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
auto& eqParam = specific.get<Parameter::Specific::equalizer>();
@@ -117,7 +116,6 @@
ndk::ScopedAStatus EqualizerSw::getParameterEqualizer(const Equalizer::Tag& tag,
Parameter::Specific* specific) {
- std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
Equalizer eqParam;
@@ -144,9 +142,14 @@
std::shared_ptr<EffectContext> EqualizerSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
- return mContext;
+ } else {
+ mContext = std::make_shared<EqualizerSwContext>(1 /* statusFmqDepth */, common);
}
- mContext = std::make_shared<EqualizerSwContext>(1 /* statusFmqDepth */, common);
+
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> EqualizerSw::getContext() {
return mContext;
}
@@ -158,13 +161,13 @@
}
// Processing method running in EffectWorker thread.
-IEffect::Status EqualizerSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status EqualizerSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
- for (int i = 0; i < process; i++) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- return {STATUS_OK, process, process};
+ return {STATUS_OK, samples, samples};
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/equalizer/EqualizerSw.h b/audio/aidl/default/equalizer/EqualizerSw.h
index aa4587a..c104a89 100644
--- a/audio/aidl/default/equalizer/EqualizerSw.h
+++ b/audio/aidl/default/equalizer/EqualizerSw.h
@@ -90,11 +90,16 @@
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ std::string getEffectName() override { return kEffectName; }
+
private:
+ const std::string kEffectName = "EqualizerSw";
std::shared_ptr<EqualizerSwContext> mContext;
/* capabilities */
const std::vector<Equalizer::BandFrequency> mBandFrequency = {{0, 30000, 120000},
@@ -115,7 +120,7 @@
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
- .name = "EqualizerSw",
+ .name = kEffectName,
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::equalizer>(kEqCap)};
diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
index fd5ea34..7e86657 100644
--- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.cpp
@@ -73,9 +73,6 @@
ndk::ScopedAStatus HapticGeneratorSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::hapticGenerator != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- std::lock_guard lg(mMutex);
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
-
mSpecificParam = specific.get<Parameter::Specific::hapticGenerator>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
return ndk::ScopedAStatus::ok();
@@ -92,9 +89,14 @@
std::shared_ptr<EffectContext> HapticGeneratorSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
- return mContext;
+ } else {
+ mContext = std::make_shared<HapticGeneratorSwContext>(1 /* statusFmqDepth */, common);
}
- mContext = std::make_shared<HapticGeneratorSwContext>(1 /* statusFmqDepth */, common);
+
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> HapticGeneratorSw::getContext() {
return mContext;
}
@@ -106,13 +108,13 @@
}
// Processing method running in EffectWorker thread.
-IEffect::Status HapticGeneratorSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status HapticGeneratorSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
- for (int i = 0; i < process; i++) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- return {STATUS_OK, process, process};
+ return {STATUS_OK, samples, samples};
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
index 518aa87..dbd6c55 100644
--- a/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
+++ b/audio/aidl/default/hapticGenerator/HapticGeneratorSw.h
@@ -47,11 +47,16 @@
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ std::string getEffectName() override { return kEffectName; }
+
private:
+ const std::string kEffectName = "HapticGeneratorSw";
std::shared_ptr<HapticGeneratorSwContext> mContext;
/* capabilities */
const HapticGenerator::Capability kCapability;
@@ -63,7 +68,7 @@
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
- .name = "HapticGeneratorSw",
+ .name = kEffectName,
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::hapticGenerator>(kCapability)};
diff --git a/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h b/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h
new file mode 100644
index 0000000..47918f0
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/AudioPolicyConfigXmlConverter.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 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 <string>
+
+#include <aidl/android/media/audio/common/AudioHalEngineConfig.h>
+#include <android_audio_policy_configuration.h>
+#include <android_audio_policy_configuration_enums.h>
+
+#include "core-impl/XmlConverter.h"
+
+namespace aidl::android::hardware::audio::core::internal {
+
+class AudioPolicyConfigXmlConverter {
+ public:
+ explicit AudioPolicyConfigXmlConverter(const std::string& configFilePath)
+ : mConverter(configFilePath, &::android::audio::policy::configuration::read) {}
+
+ std::string getError() const { return mConverter.getError(); }
+ ::android::status_t getStatus() const { return mConverter.getStatus(); }
+
+ const ::aidl::android::media::audio::common::AudioHalEngineConfig& getAidlEngineConfig();
+
+ private:
+ const std::optional<::android::audio::policy::configuration::AudioPolicyConfiguration>&
+ getXsdcConfig() const {
+ return mConverter.getXsdcConfig();
+ }
+ void addVolumeGroupstoEngineConfig();
+ void mapStreamToVolumeCurve(
+ const ::android::audio::policy::configuration::Volume& xsdcVolumeCurve);
+ void mapStreamsToVolumeCurves();
+ void parseVolumes();
+ ::aidl::android::media::audio::common::AudioHalVolumeCurve::CurvePoint convertCurvePointToAidl(
+ const std::string& xsdcCurvePoint);
+
+ ::aidl::android::media::audio::common::AudioHalVolumeCurve convertVolumeCurveToAidl(
+ const ::android::audio::policy::configuration::Volume& xsdcVolumeCurve);
+
+ ::aidl::android::media::audio::common::AudioHalEngineConfig mAidlEngineConfig;
+ XmlConverter<::android::audio::policy::configuration::AudioPolicyConfiguration> mConverter;
+ std::unordered_map<std::string, ::android::audio::policy::configuration::Reference>
+ mVolumesReferenceMap;
+ std::unordered_map<::android::audio::policy::configuration::AudioStreamType,
+ std::vector<::aidl::android::media::audio::common::AudioHalVolumeCurve>>
+ mStreamToVolumeCurvesMap;
+};
+
+} // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/include/core-impl/Config.h b/audio/aidl/default/include/core-impl/Config.h
index 4555efd..96a6cb9 100644
--- a/audio/aidl/default/include/core-impl/Config.h
+++ b/audio/aidl/default/include/core-impl/Config.h
@@ -17,11 +17,22 @@
#pragma once
#include <aidl/android/hardware/audio/core/BnConfig.h>
+#include <system/audio_config.h>
+
+#include "AudioPolicyConfigXmlConverter.h"
+#include "EngineConfigXmlConverter.h"
namespace aidl::android::hardware::audio::core {
+static const std::string kEngineConfigFileName = "audio_policy_engine_configuration.xml";
class Config : public BnConfig {
ndk::ScopedAStatus getSurroundSoundConfig(SurroundSoundConfig* _aidl_return) override;
+ ndk::ScopedAStatus getEngineConfig(
+ aidl::android::media::audio::common::AudioHalEngineConfig* _aidl_return) override;
+ internal::AudioPolicyConfigXmlConverter mAudioPolicyConverter{
+ ::android::audio_get_audio_policy_config_file()};
+ internal::EngineConfigXmlConverter mEngConfigConverter{
+ ::android::audio_find_readable_configuration_file(kEngineConfigFileName.c_str())};
};
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/EngineConfigXmlConverter.h b/audio/aidl/default/include/core-impl/EngineConfigXmlConverter.h
new file mode 100644
index 0000000..b34441d
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/EngineConfigXmlConverter.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2022 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 <string>
+#include <unordered_map>
+
+#include <utils/Errors.h>
+
+#include <android_audio_policy_engine_configuration.h>
+#include <android_audio_policy_engine_configuration_enums.h>
+
+#include "core-impl/XmlConverter.h"
+
+namespace aidl::android::hardware::audio::core::internal {
+
+class EngineConfigXmlConverter {
+ public:
+ explicit EngineConfigXmlConverter(const std::string& configFilePath)
+ : mConverter(configFilePath, &::android::audio::policy::engine::configuration::read) {
+ if (mConverter.getXsdcConfig()) {
+ init();
+ }
+ }
+
+ std::string getError() const { return mConverter.getError(); }
+ ::android::status_t getStatus() const { return mConverter.getStatus(); }
+
+ ::aidl::android::media::audio::common::AudioHalEngineConfig& getAidlEngineConfig();
+
+ private:
+ const std::optional<::android::audio::policy::engine::configuration::Configuration>&
+ getXsdcConfig() {
+ return mConverter.getXsdcConfig();
+ }
+ void init();
+ void initProductStrategyMap();
+ ::aidl::android::media::audio::common::AudioAttributes convertAudioAttributesToAidl(
+ const ::android::audio::policy::engine::configuration::AttributesType&
+ xsdcAudioAttributes);
+ ::aidl::android::media::audio::common::AudioHalAttributesGroup convertAttributesGroupToAidl(
+ const ::android::audio::policy::engine::configuration::AttributesGroup&
+ xsdcAttributesGroup);
+ ::aidl::android::media::audio::common::AudioHalCapCriterion convertCapCriterionToAidl(
+ const ::android::audio::policy::engine::configuration::CriterionType& xsdcCriterion);
+ ::aidl::android::media::audio::common::AudioHalCapCriterionType convertCapCriterionTypeToAidl(
+ const ::android::audio::policy::engine::configuration::CriterionTypeType&
+ xsdcCriterionType);
+ std::string convertCriterionTypeValueToAidl(
+ const ::android::audio::policy::engine::configuration::ValueType&
+ xsdcCriterionTypeValue);
+ ::aidl::android::media::audio::common::AudioHalVolumeCurve::CurvePoint convertCurvePointToAidl(
+ const std::string& xsdcCurvePoint);
+ ::aidl::android::media::audio::common::AudioHalProductStrategy convertProductStrategyToAidl(
+ const ::android::audio::policy::engine::configuration::ProductStrategies::
+ ProductStrategy& xsdcProductStrategy);
+ int convertProductStrategyNameToAidl(const std::string& xsdcProductStrategyName);
+ ::aidl::android::media::audio::common::AudioHalVolumeCurve convertVolumeCurveToAidl(
+ const ::android::audio::policy::engine::configuration::Volume& xsdcVolumeCurve);
+ ::aidl::android::media::audio::common::AudioHalVolumeGroup convertVolumeGroupToAidl(
+ const ::android::audio::policy::engine::configuration::VolumeGroupsType::VolumeGroup&
+ xsdcVolumeGroup);
+
+ ::aidl::android::media::audio::common::AudioHalEngineConfig mAidlEngineConfig;
+ XmlConverter<::android::audio::policy::engine::configuration::Configuration> mConverter;
+ std::unordered_map<std::string,
+ ::android::audio::policy::engine::configuration::AttributesRefType>
+ mAttributesReferenceMap;
+ std::unordered_map<std::string, ::android::audio::policy::engine::configuration::VolumeRef>
+ mVolumesReferenceMap;
+ std::unordered_map<std::string, int> mProductStrategyMap;
+ int mNextVendorStrategy = ::aidl::android::media::audio::common::AudioHalProductStrategy::
+ VENDOR_STRATEGY_ID_START;
+ std::optional<int> mDefaultProductStrategyId;
+};
+
+} // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/include/core-impl/XmlConverter.h b/audio/aidl/default/include/core-impl/XmlConverter.h
new file mode 100644
index 0000000..ec23edb
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/XmlConverter.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2022 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 <optional>
+#include <string>
+#include <unordered_map>
+
+#include <system/audio_config.h>
+#include <utils/Errors.h>
+
+namespace aidl::android::hardware::audio::core::internal {
+
+template <typename T>
+class XmlConverter {
+ public:
+ XmlConverter(const std::string& configFilePath,
+ std::function<std::optional<T>(const char*)> readXmlConfig)
+ : XmlConverter(configFilePath,
+ ::android::audio_is_readable_configuration_file(configFilePath.c_str()),
+ readXmlConfig) {}
+
+ const ::android::status_t& getStatus() const { return mStatus; }
+
+ const std::string& getError() const { return mErrorMessage; }
+
+ const std::optional<T>& getXsdcConfig() const { return mXsdcConfig; }
+
+ private:
+ XmlConverter(const std::string& configFilePath, const bool& isReadableConfigFile,
+ const std::function<std::optional<T>(const char*)>& readXmlConfig)
+ : mXsdcConfig{isReadableConfigFile ? readXmlConfig(configFilePath.c_str()) : std::nullopt},
+ mStatus(mXsdcConfig ? ::android::OK : ::android::NO_INIT),
+ mErrorMessage(generateError(configFilePath, isReadableConfigFile, mStatus)) {}
+
+ static std::string generateError(const std::string& configFilePath,
+ const bool& isReadableConfigFile,
+ const ::android::status_t& status) {
+ std::string errorMessage;
+ if (status != ::android::OK) {
+ if (!isReadableConfigFile) {
+ errorMessage = "Could not read requested config file:" + configFilePath;
+ } else {
+ errorMessage = "Invalid config file: " + configFilePath;
+ }
+ }
+ return errorMessage;
+ }
+
+ const std::optional<T> mXsdcConfig;
+ const ::android::status_t mStatus;
+ const std::string mErrorMessage;
+};
+
+/**
+ * Converts a vector of an xsd wrapper type to a flat vector of the
+ * corresponding AIDL type.
+ *
+ * Wrapper types are used in order to have well-formed xIncludes. In the
+ * example below, Modules is the wrapper type for Module.
+ * <Modules>
+ * <Module> ... </Module>
+ * <Module> ... </Module>
+ * </Modules>
+ */
+template <typename W, typename X, typename A>
+static std::vector<A> convertWrappedCollectionToAidl(
+ const std::vector<W>& xsdcWrapperTypeVec,
+ std::function<const std::vector<X>&(const W&)> getInnerTypeVec,
+ std::function<A(const X&)> convertToAidl) {
+ std::vector<A> resultAidlTypeVec;
+ if (!xsdcWrapperTypeVec.empty()) {
+ /*
+ * xsdcWrapperTypeVec likely only contains one element; that is, it's
+ * likely that all the inner types that we need to convert are inside of
+ * xsdcWrapperTypeVec[0].
+ */
+ resultAidlTypeVec.reserve(getInnerTypeVec(xsdcWrapperTypeVec[0]).size());
+ for (const W& xsdcWrapperType : xsdcWrapperTypeVec) {
+ std::transform(getInnerTypeVec(xsdcWrapperType).begin(),
+ getInnerTypeVec(xsdcWrapperType).end(),
+ std::back_inserter(resultAidlTypeVec), convertToAidl);
+ }
+ }
+ return resultAidlTypeVec;
+}
+
+template <typename X, typename A>
+static std::vector<A> convertCollectionToAidl(const std::vector<X>& xsdcTypeVec,
+ std::function<A(const X&)> convertToAidl) {
+ std::vector<A> resultAidlTypeVec;
+ resultAidlTypeVec.reserve(xsdcTypeVec.size());
+ std::transform(xsdcTypeVec.begin(), xsdcTypeVec.end(), std::back_inserter(resultAidlTypeVec),
+ convertToAidl);
+ return resultAidlTypeVec;
+}
+
+/**
+ * Generates a map of xsd references, keyed by reference name, given a
+ * vector of wrapper types for the reference.
+ *
+ * Wrapper types are used in order to have well-formed xIncludes. In the
+ * example below, Wrapper is the wrapper type for Reference.
+ * <Wrapper>
+ * <Reference> ... </Reference>
+ * <Reference> ... </Reference>
+ * </Wrapper>
+ */
+template <typename W, typename R>
+static std::unordered_map<std::string, R> generateReferenceMap(
+ const std::vector<W>& xsdcWrapperTypeVec) {
+ std::unordered_map<std::string, R> resultMap;
+ if (!xsdcWrapperTypeVec.empty()) {
+ /*
+ * xsdcWrapperTypeVec likely only contains one element; that is, it's
+ * likely that all the inner types that we need to convert are inside of
+ * xsdcWrapperTypeVec[0].
+ */
+ resultMap.reserve(xsdcWrapperTypeVec[0].getReference().size());
+ for (const W& xsdcWrapperType : xsdcWrapperTypeVec) {
+ for (const R& xsdcReference : xsdcWrapperType.getReference()) {
+ resultMap.insert({xsdcReference.getName(), xsdcReference});
+ }
+ }
+ }
+ return resultMap;
+}
+} // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/include/effect-impl/EffectContext.h b/audio/aidl/default/include/effect-impl/EffectContext.h
index f608e12..95645d5 100644
--- a/audio/aidl/default/include/effect-impl/EffectContext.h
+++ b/audio/aidl/default/include/effect-impl/EffectContext.h
@@ -16,16 +16,13 @@
#pragma once
#include <Utils.h>
-#include <android-base/logging.h>
-#include <utils/Log.h>
-#include <cstddef>
-#include <cstdint>
#include <memory>
-#include <utility>
#include <vector>
-#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <android-base/logging.h>
#include <fmq/AidlMessageQueue.h>
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
#include "EffectTypes.h"
namespace aidl::android::hardware::audio::effect {
@@ -74,13 +71,10 @@
std::shared_ptr<DataMQ> getOutputDataFmq() { return mOutputMQ; }
float* getWorkBuffer() { return static_cast<float*>(mWorkBuffer.data()); }
- // TODO: update with actual available size
- size_t availableToRead() { return mWorkBuffer.capacity(); }
- size_t availableToWrite() { return mWorkBuffer.capacity(); }
// reset buffer status by abandon all data and status in FMQ
void resetBuffer() {
- auto buffer = getWorkBuffer();
+ auto buffer = static_cast<float*>(mWorkBuffer.data());
std::vector<IEffect::Status> status(mStatusMQ->availableToRead());
mInputMQ->read(buffer, mInputMQ->availableToRead());
mOutputMQ->read(buffer, mOutputMQ->availableToRead());
@@ -89,9 +83,9 @@
void dupeFmq(IEffect::OpenEffectReturn* effectRet) {
if (effectRet) {
- effectRet->statusMQ = getStatusFmq()->dupeDesc();
- effectRet->inputDataMQ = getInputDataFmq()->dupeDesc();
- effectRet->outputDataMQ = getOutputDataFmq()->dupeDesc();
+ effectRet->statusMQ = mStatusMQ->dupeDesc();
+ effectRet->inputDataMQ = mInputMQ->dupeDesc();
+ effectRet->outputDataMQ = mOutputMQ->dupeDesc();
}
}
size_t getInputFrameSize() { return mInputFrameSize; }
@@ -138,7 +132,8 @@
protected:
// common parameters
int mSessionId = INVALID_AUDIO_SESSION_ID;
- size_t mInputFrameSize, mOutputFrameSize;
+ size_t mInputFrameSize;
+ size_t mOutputFrameSize;
Parameter::Common mCommon;
aidl::android::media::audio::common::AudioDeviceDescription mOutputDevice;
aidl::android::media::audio::common::AudioMode mMode;
diff --git a/audio/aidl/default/include/effect-impl/EffectImpl.h b/audio/aidl/default/include/effect-impl/EffectImpl.h
index d9825da..f5e2aec 100644
--- a/audio/aidl/default/include/effect-impl/EffectImpl.h
+++ b/audio/aidl/default/include/effect-impl/EffectImpl.h
@@ -15,45 +15,35 @@
*/
#pragma once
-#include <aidl/android/hardware/audio/effect/BnEffect.h>
-#include <fmq/AidlMessageQueue.h>
#include <cstdlib>
#include <memory>
-#include <mutex>
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "EffectContext.h"
+#include "EffectThread.h"
#include "EffectTypes.h"
#include "effect-impl/EffectContext.h"
+#include "effect-impl/EffectThread.h"
#include "effect-impl/EffectTypes.h"
-#include "effect-impl/EffectWorker.h"
namespace aidl::android::hardware::audio::effect {
-class EffectImpl : public BnEffect, public EffectWorker {
+class EffectImpl : public BnEffect, public EffectThread {
public:
EffectImpl() = default;
virtual ~EffectImpl() = default;
- /**
- * Each effect implementation CAN override these methods if necessary
- * If you would like implement IEffect::open completely, override EffectImpl::open(), if you
- * want to keep most of EffectImpl logic but have a little customize, try override openImpl().
- * openImpl() will be called at the beginning of EffectImpl::open() without lock protection.
- *
- * Same for closeImpl().
- */
virtual ndk::ScopedAStatus open(const Parameter::Common& common,
const std::optional<Parameter::Specific>& specific,
OpenEffectReturn* ret) override;
virtual ndk::ScopedAStatus close() override;
virtual ndk::ScopedAStatus command(CommandId id) override;
- virtual ndk::ScopedAStatus commandStart() { return ndk::ScopedAStatus::ok(); }
- virtual ndk::ScopedAStatus commandStop() { return ndk::ScopedAStatus::ok(); }
- virtual ndk::ScopedAStatus commandReset() { return ndk::ScopedAStatus::ok(); }
virtual ndk::ScopedAStatus getState(State* state) override;
virtual ndk::ScopedAStatus setParameter(const Parameter& param) override;
virtual ndk::ScopedAStatus getParameter(const Parameter::Id& id, Parameter* param) override;
- virtual IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
virtual ndk::ScopedAStatus setParameterCommon(const Parameter& param);
virtual ndk::ScopedAStatus getParameterCommon(const Parameter::Tag& tag, Parameter* param);
@@ -63,21 +53,32 @@
virtual ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) = 0;
virtual ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) = 0;
+
+ virtual std::string getEffectName() = 0;
+ virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+
+ /**
+ * Effect context methods must be implemented by each effect.
+ * Each effect can derive from EffectContext and define its own context, but must upcast to
+ * EffectContext for EffectImpl to use.
+ */
virtual std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) = 0;
+ virtual std::shared_ptr<EffectContext> getContext() = 0;
virtual RetCode releaseContext() = 0;
protected:
- /*
- * Lock is required if effectProcessImpl (which is running in an independent thread) needs to
- * access state and parameters.
- */
- std::mutex mMutex;
- State mState GUARDED_BY(mMutex) = State::INIT;
+ State mState = State::INIT;
IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
void cleanUp();
- private:
- std::shared_ptr<EffectContext> mContext GUARDED_BY(mMutex);
+ /**
+ * Optional CommandId handling methods for effects to override.
+ * For CommandId::START, EffectImpl call commandImpl before starting the EffectThread
+ * processing.
+ * For CommandId::STOP and CommandId::RESET, EffectImpl call commandImpl after stop the
+ * EffectThread processing.
+ */
+ virtual ndk::ScopedAStatus commandImpl(CommandId id);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/effect-impl/EffectThread.h b/audio/aidl/default/include/effect-impl/EffectThread.h
index 09a0000..4b6cecd 100644
--- a/audio/aidl/default/include/effect-impl/EffectThread.h
+++ b/audio/aidl/default/include/effect-impl/EffectThread.h
@@ -22,6 +22,7 @@
#include <android-base/thread_annotations.h>
#include <system/thread_defs.h>
+#include "effect-impl/EffectContext.h"
#include "effect-impl/EffectTypes.h"
namespace aidl::android::hardware::audio::effect {
@@ -33,7 +34,7 @@
virtual ~EffectThread();
// called by effect implementation.
- RetCode createThread(const std::string& name,
+ RetCode createThread(std::shared_ptr<EffectContext> context, const std::string& name,
const int priority = ANDROID_PRIORITY_URGENT_AUDIO);
RetCode destroyThread();
RetCode startThread();
@@ -42,15 +43,43 @@
// Will call process() in a loop if the thread is running.
void threadLoop();
- // User of EffectThread must implement the effect processing logic in this method.
- virtual void process() = 0;
- const int MAX_TASK_COMM_LEN = 15;
+ /**
+ * @brief effectProcessImpl is running in worker thread which created in EffectThread.
+ *
+ * Effect implementation should think about concurrency in the implementation if necessary.
+ * Parameter setting usually implemented in context (derived from EffectContext), and some
+ * parameter maybe used in the processing, then effect implementation should consider using a
+ * mutex to protect these parameter.
+ *
+ * EffectThread will make sure effectProcessImpl only be called after startThread() successful
+ * and before stopThread() successful.
+ *
+ * @param in address of input float buffer.
+ * @param out address of output float buffer.
+ * @param samples number of samples to process.
+ * @return IEffect::Status
+ */
+ virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) = 0;
+
+ /**
+ * The default EffectThread::process() implementation doesn't need to lock. It will only
+ * access the FMQ and mWorkBuffer in EffectContext, since they will only be changed in
+ * EffectImpl IEffect::open() (in this case EffectThread just created and not running yet) and
+ * IEffect::command(CommandId::RESET) (in this case EffectThread already stopped).
+ *
+ * process() call effectProcessImpl for effect processing, and because effectProcessImpl is
+ * implemented by effects, process() must not hold lock before call into effectProcessImpl to
+ * avoid deadlock.
+ */
+ virtual void process();
private:
- std::mutex mMutex;
+ const int kMaxTaskNameLen = 15;
+ std::mutex mThreadMutex;
std::condition_variable mCv;
- bool mExit GUARDED_BY(mMutex) = false;
- bool mStop GUARDED_BY(mMutex) = true;
+ bool mExit GUARDED_BY(mThreadMutex) = false;
+ bool mStop GUARDED_BY(mThreadMutex) = true;
+ std::shared_ptr<EffectContext> mThreadContext GUARDED_BY(mThreadMutex);
std::thread mThread;
int mPriority;
std::string mName;
diff --git a/audio/aidl/default/include/effect-impl/EffectWorker.h b/audio/aidl/default/include/effect-impl/EffectWorker.h
index 6a78eab..b456817 100644
--- a/audio/aidl/default/include/effect-impl/EffectWorker.h
+++ b/audio/aidl/default/include/effect-impl/EffectWorker.h
@@ -63,7 +63,7 @@
// must implement by each effect implementation
// TODO: consider if this interface need adjustment to handle in-place processing
- virtual IEffect::Status effectProcessImpl(float* in, float* out, int processSamples) = 0;
+ virtual IEffect::Status effectProcessImpl(float* in, float* out, int samples) = 0;
private:
// make sure the context only set once.
diff --git a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
index 9d2b978..4015e61 100644
--- a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
+++ b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.cpp
@@ -73,7 +73,6 @@
ndk::ScopedAStatus LoudnessEnhancerSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::loudnessEnhancer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
auto& leParam = specific.get<Parameter::Specific::loudnessEnhancer>();
@@ -113,7 +112,6 @@
ndk::ScopedAStatus LoudnessEnhancerSw::getParameterLoudnessEnhancer(
const LoudnessEnhancer::Tag& tag, Parameter::Specific* specific) {
- std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
LoudnessEnhancer leParam;
@@ -136,9 +134,14 @@
std::shared_ptr<EffectContext> LoudnessEnhancerSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
- return mContext;
+ } else {
+ mContext = std::make_shared<LoudnessEnhancerSwContext>(1 /* statusFmqDepth */, common);
}
- mContext = std::make_shared<LoudnessEnhancerSwContext>(1 /* statusFmqDepth */, common);
+
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> LoudnessEnhancerSw::getContext() {
return mContext;
}
@@ -150,13 +153,13 @@
}
// Processing method running in EffectWorker thread.
-IEffect::Status LoudnessEnhancerSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status LoudnessEnhancerSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
- for (int i = 0; i < process; i++) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- return {STATUS_OK, process, process};
+ return {STATUS_OK, samples, samples};
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
index 856bf0b..2aa4953 100644
--- a/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
+++ b/audio/aidl/default/loudnessEnhancer/LoudnessEnhancerSw.h
@@ -56,11 +56,16 @@
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ std::string getEffectName() override { return kEffectName; }
+
private:
+ const std::string kEffectName = "LoudnessEnhancerSw";
std::shared_ptr<LoudnessEnhancerSwContext> mContext;
/* capabilities */
const LoudnessEnhancer::Capability kCapability;
@@ -72,7 +77,7 @@
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
- .name = "LoudnessEnhancerSw",
+ .name = kEffectName,
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::loudnessEnhancer>(kCapability)};
diff --git a/audio/aidl/default/main.cpp b/audio/aidl/default/main.cpp
index 7786cc6..48067a2 100644
--- a/audio/aidl/default/main.cpp
+++ b/audio/aidl/default/main.cpp
@@ -17,14 +17,14 @@
#include <cstdlib>
#include <ctime>
-#include "core-impl/Config.h"
-#include "core-impl/Module.h"
-
#include <android-base/logging.h>
#include <android/binder_ibinder_platform.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
+#include "core-impl/Config.h"
+#include "core-impl/Module.h"
+
using aidl::android::hardware::audio::core::Config;
using aidl::android::hardware::audio::core::Module;
diff --git a/audio/aidl/default/presetReverb/PresetReverbSw.cpp b/audio/aidl/default/presetReverb/PresetReverbSw.cpp
index 069d0ff..e1f505e 100644
--- a/audio/aidl/default/presetReverb/PresetReverbSw.cpp
+++ b/audio/aidl/default/presetReverb/PresetReverbSw.cpp
@@ -73,8 +73,6 @@
ndk::ScopedAStatus PresetReverbSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::reverb != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- std::lock_guard lg(mMutex);
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
mSpecificParam = specific.get<Parameter::Specific::reverb>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
@@ -92,9 +90,14 @@
std::shared_ptr<EffectContext> PresetReverbSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
- return mContext;
+ } else {
+ mContext = std::make_shared<PresetReverbSwContext>(1 /* statusFmqDepth */, common);
}
- mContext = std::make_shared<PresetReverbSwContext>(1 /* statusFmqDepth */, common);
+
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> PresetReverbSw::getContext() {
return mContext;
}
@@ -106,13 +109,13 @@
}
// Processing method running in EffectWorker thread.
-IEffect::Status PresetReverbSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status PresetReverbSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
- for (int i = 0; i < process; i++) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- return {STATUS_OK, process, process};
+ return {STATUS_OK, samples, samples};
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/presetReverb/PresetReverbSw.h b/audio/aidl/default/presetReverb/PresetReverbSw.h
index 75a5a94..6fd3a9e 100644
--- a/audio/aidl/default/presetReverb/PresetReverbSw.h
+++ b/audio/aidl/default/presetReverb/PresetReverbSw.h
@@ -47,11 +47,16 @@
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ std::string getEffectName() override { return kEffectName; }
+
private:
+ const std::string kEffectName = "PresetReverbSw";
std::shared_ptr<PresetReverbSwContext> mContext;
/* capabilities */
const Reverb::Capability kCapability;
@@ -63,7 +68,7 @@
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
- .name = "PresetReverbSw",
+ .name = kEffectName,
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::reverb>(kCapability)};
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.cpp b/audio/aidl/default/virtualizer/VirtualizerSw.cpp
index 9688fc8..125fbee 100644
--- a/audio/aidl/default/virtualizer/VirtualizerSw.cpp
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.cpp
@@ -73,8 +73,6 @@
ndk::ScopedAStatus VirtualizerSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::virtualizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- std::lock_guard lg(mMutex);
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
mSpecificParam = specific.get<Parameter::Specific::virtualizer>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
@@ -92,9 +90,14 @@
std::shared_ptr<EffectContext> VirtualizerSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
- return mContext;
+ } else {
+ mContext = std::make_shared<VirtualizerSwContext>(1 /* statusFmqDepth */, common);
}
- mContext = std::make_shared<VirtualizerSwContext>(1 /* statusFmqDepth */, common);
+
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> VirtualizerSw::getContext() {
return mContext;
}
@@ -106,13 +109,13 @@
}
// Processing method running in EffectWorker thread.
-IEffect::Status VirtualizerSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status VirtualizerSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
- for (int i = 0; i < process; i++) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- return {STATUS_OK, process, process};
+ return {STATUS_OK, samples, samples};
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.h b/audio/aidl/default/virtualizer/VirtualizerSw.h
index e4de8b3..e77adef 100644
--- a/audio/aidl/default/virtualizer/VirtualizerSw.h
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.h
@@ -47,11 +47,16 @@
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ std::string getEffectName() override { return kEffectName; }
+
private:
+ const std::string kEffectName = "VirtualizerSw";
std::shared_ptr<VirtualizerSwContext> mContext;
/* capabilities */
const Virtualizer::Capability kCapability;
@@ -63,7 +68,7 @@
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
- .name = "VirtualizerSw",
+ .name = kEffectName,
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::virtualizer>(kCapability)};
diff --git a/audio/aidl/default/visualizer/VisualizerSw.cpp b/audio/aidl/default/visualizer/VisualizerSw.cpp
index 24a7bef..ffdf325 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.cpp
+++ b/audio/aidl/default/visualizer/VisualizerSw.cpp
@@ -73,8 +73,6 @@
ndk::ScopedAStatus VisualizerSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::visualizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- std::lock_guard lg(mMutex);
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
mSpecificParam = specific.get<Parameter::Specific::visualizer>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
@@ -92,9 +90,14 @@
std::shared_ptr<EffectContext> VisualizerSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
- return mContext;
+ } else {
+ mContext = std::make_shared<VisualizerSwContext>(1 /* statusFmqDepth */, common);
}
- mContext = std::make_shared<VisualizerSwContext>(1 /* statusFmqDepth */, common);
+
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> VisualizerSw::getContext() {
return mContext;
}
@@ -106,13 +109,13 @@
}
// Processing method running in EffectWorker thread.
-IEffect::Status VisualizerSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status VisualizerSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
- for (int i = 0; i < process; i++) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- return {STATUS_OK, process, process};
+ return {STATUS_OK, samples, samples};
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/visualizer/VisualizerSw.h b/audio/aidl/default/visualizer/VisualizerSw.h
index bccd6e9..18bb10c 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.h
+++ b/audio/aidl/default/visualizer/VisualizerSw.h
@@ -47,11 +47,16 @@
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ std::string getEffectName() override { return kEffectName; }
+
private:
+ const std::string kEffectName = "VisualizerSw";
std::shared_ptr<VisualizerSwContext> mContext;
/* capabilities */
const Visualizer::Capability kCapability;
@@ -63,7 +68,7 @@
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
- .name = "VisualizerSw",
+ .name = kEffectName,
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::visualizer>(kCapability)};
diff --git a/audio/aidl/default/volume/VolumeSw.cpp b/audio/aidl/default/volume/VolumeSw.cpp
index b8af921..4cc4f08 100644
--- a/audio/aidl/default/volume/VolumeSw.cpp
+++ b/audio/aidl/default/volume/VolumeSw.cpp
@@ -73,8 +73,6 @@
ndk::ScopedAStatus VolumeSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::volume != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- std::lock_guard lg(mMutex);
- RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
mSpecificParam = specific.get<Parameter::Specific::volume>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
@@ -92,9 +90,14 @@
std::shared_ptr<EffectContext> VolumeSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
- return mContext;
+ } else {
+ mContext = std::make_shared<VolumeSwContext>(1 /* statusFmqDepth */, common);
}
- mContext = std::make_shared<VolumeSwContext>(1 /* statusFmqDepth */, common);
+
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> VolumeSw::getContext() {
return mContext;
}
@@ -106,13 +109,13 @@
}
// Processing method running in EffectWorker thread.
-IEffect::Status VolumeSw::effectProcessImpl(float* in, float* out, int process) {
+IEffect::Status VolumeSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
- for (int i = 0; i < process; i++) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
+ for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- return {STATUS_OK, process, process};
+ return {STATUS_OK, samples, samples};
}
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/volume/VolumeSw.h b/audio/aidl/default/volume/VolumeSw.h
index 86e01c1..b9e554b 100644
--- a/audio/aidl/default/volume/VolumeSw.h
+++ b/audio/aidl/default/volume/VolumeSw.h
@@ -47,11 +47,16 @@
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ std::string getEffectName() override { return kEffectName; }
+
private:
+ const std::string kEffectName = "VolumeSw";
std::shared_ptr<VolumeSwContext> mContext;
/* capabilities */
const Volume::Capability kCapability;
@@ -63,7 +68,7 @@
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
- .name = "VolumeSw",
+ .name = kEffectName,
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::volume>(kCapability)};
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index 03e9fca..068742d 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -49,7 +49,8 @@
],
srcs: [
"ModuleConfig.cpp",
- "VtsHalAudioCoreTargetTest.cpp",
+ "VtsHalAudioCoreConfigTargetTest.cpp",
+ "VtsHalAudioCoreModuleTargetTest.cpp",
],
}
@@ -66,6 +67,12 @@
}
cc_test {
+ name: "VtsHalBassBoostTargetTest",
+ defaults: ["VtsHalAudioTargetTestDefaults"],
+ srcs: ["VtsHalBassBoostTargetTest.cpp"],
+}
+
+cc_test {
name: "VtsHalEqualizerTargetTest",
defaults: ["VtsHalAudioTargetTestDefaults"],
srcs: ["VtsHalEqualizerTargetTest.cpp"],
diff --git a/audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp
new file mode 100644
index 0000000..bf73648
--- /dev/null
+++ b/audio/aidl/vts/VtsHalAudioCoreConfigTargetTest.cpp
@@ -0,0 +1,333 @@
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#define LOG_TAG "VtsHalAudioCore.Config"
+
+#include <Utils.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/audio/core/IConfig.h>
+
+#include "AudioHalBinderServiceUtil.h"
+#include "TestUtils.h"
+
+using namespace android;
+using aidl::android::hardware::audio::core::IConfig;
+using aidl::android::media::audio::common::AudioAttributes;
+using aidl::android::media::audio::common::AudioFlag;
+using aidl::android::media::audio::common::AudioHalAttributesGroup;
+using aidl::android::media::audio::common::AudioHalCapCriterion;
+using aidl::android::media::audio::common::AudioHalCapCriterionType;
+using aidl::android::media::audio::common::AudioHalEngineConfig;
+using aidl::android::media::audio::common::AudioHalProductStrategy;
+using aidl::android::media::audio::common::AudioHalVolumeCurve;
+using aidl::android::media::audio::common::AudioHalVolumeGroup;
+using aidl::android::media::audio::common::AudioProductStrategyType;
+using aidl::android::media::audio::common::AudioSource;
+using aidl::android::media::audio::common::AudioStreamType;
+using aidl::android::media::audio::common::AudioUsage;
+
+class AudioCoreConfig : public testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override { ASSERT_NO_FATAL_FAILURE(ConnectToService()); }
+ void ConnectToService() {
+ mConfig = IConfig::fromBinder(mBinderUtil.connectToService(GetParam()));
+ ASSERT_NE(mConfig, nullptr);
+ }
+
+ void RestartService() {
+ ASSERT_NE(mConfig, nullptr);
+ mEngineConfig.reset();
+ mConfig = IConfig::fromBinder(mBinderUtil.restartService());
+ ASSERT_NE(mConfig, nullptr);
+ }
+
+ void SetUpEngineConfig() {
+ if (mEngineConfig == nullptr) {
+ auto tempConfig = std::make_unique<AudioHalEngineConfig>();
+ ASSERT_IS_OK(mConfig->getEngineConfig(tempConfig.get()));
+ mEngineConfig = std::move(tempConfig);
+ }
+ }
+
+ static bool IsProductStrategyTypeReservedForSystemUse(const AudioProductStrategyType& pst) {
+ switch (pst) {
+ case AudioProductStrategyType::SYS_RESERVED_NONE:
+ case AudioProductStrategyType::SYS_RESERVED_REROUTING:
+ case AudioProductStrategyType::SYS_RESERVED_CALL_ASSISTANT:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ static bool IsStreamTypeReservedForSystemUse(const AudioStreamType& streamType) {
+ switch (streamType) {
+ case AudioStreamType::SYS_RESERVED_DEFAULT:
+ case AudioStreamType::SYS_RESERVED_REROUTING:
+ case AudioStreamType::SYS_RESERVED_PATCH:
+ case AudioStreamType::CALL_ASSISTANT:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ static bool IsAudioUsageValid(const AudioUsage& usage) {
+ switch (usage) {
+ case AudioUsage::INVALID:
+ case AudioUsage::SYS_RESERVED_NOTIFICATION_COMMUNICATION_REQUEST:
+ case AudioUsage::SYS_RESERVED_NOTIFICATION_COMMUNICATION_INSTANT:
+ case AudioUsage::SYS_RESERVED_NOTIFICATION_COMMUNICATION_DELAYED:
+ return false;
+ default:
+ return true;
+ }
+ }
+
+ static bool IsAudioSourceValid(const AudioSource& source) {
+ return (source != AudioSource::SYS_RESERVED_INVALID);
+ }
+
+ static const std::unordered_set<int>& GetSupportedAudioProductStrategyTypes() {
+ static const std::unordered_set<int> supportedAudioProductStrategyTypes = []() {
+ std::unordered_set<int> supportedStrategyTypes;
+ for (const auto& audioProductStrategyType :
+ ndk::enum_range<AudioProductStrategyType>()) {
+ if (!IsProductStrategyTypeReservedForSystemUse(audioProductStrategyType)) {
+ supportedStrategyTypes.insert(static_cast<int>(audioProductStrategyType));
+ }
+ }
+ return supportedStrategyTypes;
+ }();
+ return supportedAudioProductStrategyTypes;
+ }
+
+ static int GetSupportedAudioFlagsMask() {
+ static const int supportedAudioFlagsMask = []() {
+ int mask = 0;
+ for (const auto& audioFlag : ndk::enum_range<AudioFlag>()) {
+ mask |= static_cast<int>(audioFlag);
+ }
+ return mask;
+ }();
+ return supportedAudioFlagsMask;
+ }
+
+ /**
+ * Verify streamType is not INVALID if using default engine.
+ * Verify that streamType is a valid AudioStreamType if the associated
+ * volumeGroup minIndex/maxIndex is INDEX_DEFERRED_TO_AUDIO_SERVICE.
+ */
+ void ValidateAudioStreamType(const AudioStreamType& streamType,
+ const AudioHalVolumeGroup& associatedVolumeGroup) {
+ EXPECT_FALSE(IsStreamTypeReservedForSystemUse(streamType));
+ if (!mEngineConfig->capSpecificConfig ||
+ associatedVolumeGroup.minIndex ==
+ AudioHalVolumeGroup::INDEX_DEFERRED_TO_AUDIO_SERVICE) {
+ EXPECT_NE(streamType, AudioStreamType::INVALID);
+ }
+ }
+
+ /**
+ * Verify contained enum types are valid.
+ */
+ void ValidateAudioAttributes(const AudioAttributes& attributes) {
+ // No need to check contentType; there are no INVALID or SYS_RESERVED values
+ EXPECT_TRUE(IsAudioUsageValid(attributes.usage));
+ EXPECT_TRUE(IsAudioSourceValid(attributes.source));
+ EXPECT_EQ(attributes.flags & ~GetSupportedAudioFlagsMask(), 0);
+ }
+
+ /**
+ * Verify volumeGroupName corresponds to an AudioHalVolumeGroup.
+ * Validate contained types.
+ */
+ void ValidateAudioHalAttributesGroup(
+ const AudioHalAttributesGroup& attributesGroup,
+ std::unordered_map<std::string, const AudioHalVolumeGroup&>& volumeGroupMap,
+ std::unordered_set<std::string>& volumeGroupsUsedInStrategies) {
+ bool isVolumeGroupNameValid = volumeGroupMap.count(attributesGroup.volumeGroupName);
+ EXPECT_TRUE(isVolumeGroupNameValid);
+ EXPECT_NO_FATAL_FAILURE(ValidateAudioStreamType(
+ attributesGroup.streamType, volumeGroupMap.at(attributesGroup.volumeGroupName)));
+ if (isVolumeGroupNameValid) {
+ volumeGroupsUsedInStrategies.insert(attributesGroup.volumeGroupName);
+ }
+ for (const AudioAttributes& attr : attributesGroup.attributes) {
+ EXPECT_NO_FATAL_FAILURE(ValidateAudioAttributes(attr));
+ }
+ }
+
+ /**
+ * Default engine: verify productStrategy.id is valid AudioProductStrategyType.
+ * CAP engine: verify productStrategy.id is either valid AudioProductStrategyType
+ * or is >= VENDOR_STRATEGY_ID_START.
+ * Validate contained types.
+ */
+ void ValidateAudioHalProductStrategy(
+ const AudioHalProductStrategy& strategy,
+ std::unordered_map<std::string, const AudioHalVolumeGroup&>& volumeGroupMap,
+ std::unordered_set<std::string>& volumeGroupsUsedInStrategies) {
+ if (!mEngineConfig->capSpecificConfig ||
+ (strategy.id < AudioHalProductStrategy::VENDOR_STRATEGY_ID_START)) {
+ EXPECT_NE(GetSupportedAudioProductStrategyTypes().find(strategy.id),
+ GetSupportedAudioProductStrategyTypes().end());
+ }
+ for (const AudioHalAttributesGroup& attributesGroup : strategy.attributesGroups) {
+ EXPECT_NO_FATAL_FAILURE(ValidateAudioHalAttributesGroup(attributesGroup, volumeGroupMap,
+ volumeGroupsUsedInStrategies));
+ }
+ }
+
+ /**
+ * Verify curve point index is in [CurvePoint::MIN_INDEX, CurvePoint::MAX_INDEX].
+ */
+ void ValidateAudioHalVolumeCurve(const AudioHalVolumeCurve& volumeCurve) {
+ for (const AudioHalVolumeCurve::CurvePoint& curvePoint : volumeCurve.curvePoints) {
+ EXPECT_TRUE(curvePoint.index >= AudioHalVolumeCurve::CurvePoint::MIN_INDEX);
+ EXPECT_TRUE(curvePoint.index <= AudioHalVolumeCurve::CurvePoint::MAX_INDEX);
+ }
+ }
+
+ /**
+ * Verify minIndex, maxIndex are non-negative.
+ * Verify minIndex <= maxIndex.
+ * Verify no two volume curves use the same device category.
+ * Validate contained types.
+ */
+ void ValidateAudioHalVolumeGroup(const AudioHalVolumeGroup& volumeGroup) {
+ /**
+ * Legacy volume curves in audio_policy_configuration.xsd don't use
+ * minIndex or maxIndex. Use of audio_policy_configuration.xml still
+ * allows, and in some cases, relies on, AudioService to provide the min
+ * and max indices for a volumeGroup. From the VTS perspective, there is
+ * no way to differentiate between use of audio_policy_configuration.xml
+ * or audio_policy_engine_configuration.xml, as either one can be used
+ * for the default audio policy engine.
+ */
+ if (volumeGroup.minIndex != AudioHalVolumeGroup::INDEX_DEFERRED_TO_AUDIO_SERVICE ||
+ volumeGroup.maxIndex != AudioHalVolumeGroup::INDEX_DEFERRED_TO_AUDIO_SERVICE) {
+ EXPECT_TRUE(volumeGroup.minIndex >= 0);
+ EXPECT_TRUE(volumeGroup.maxIndex >= 0);
+ }
+ EXPECT_TRUE(volumeGroup.minIndex <= volumeGroup.maxIndex);
+ std::unordered_set<AudioHalVolumeCurve::DeviceCategory> deviceCategorySet;
+ for (const AudioHalVolumeCurve& volumeCurve : volumeGroup.volumeCurves) {
+ EXPECT_TRUE(deviceCategorySet.insert(volumeCurve.deviceCategory).second);
+ EXPECT_NO_FATAL_FAILURE(ValidateAudioHalVolumeCurve(volumeCurve));
+ }
+ }
+
+ /**
+ * Verify defaultLiteralValue is empty for inclusive criterion.
+ */
+ void ValidateAudioHalCapCriterion(const AudioHalCapCriterion& criterion,
+ const AudioHalCapCriterionType& criterionType) {
+ if (criterionType.isInclusive) {
+ EXPECT_TRUE(criterion.defaultLiteralValue.empty());
+ }
+ }
+
+ /**
+ * Verify values only contain alphanumeric characters.
+ */
+ void ValidateAudioHalCapCriterionType(const AudioHalCapCriterionType& criterionType) {
+ auto isNotAlnum = [](const char& c) { return !isalnum(c); };
+ for (const std::string& value : criterionType.values) {
+ EXPECT_EQ(find_if(value.begin(), value.end(), isNotAlnum), value.end());
+ }
+ }
+
+ /**
+ * Verify each criterionType has a unique name.
+ * Verify each criterion has a unique name.
+ * Verify each criterion maps to a criterionType.
+ * Verify each criterionType is used in a criterion.
+ * Validate contained types.
+ */
+ void ValidateCapSpecificConfig(const AudioHalEngineConfig::CapSpecificConfig& capCfg) {
+ EXPECT_FALSE(capCfg.criteria.empty());
+ EXPECT_FALSE(capCfg.criterionTypes.empty());
+ std::unordered_map<std::string, AudioHalCapCriterionType> criterionTypeMap;
+ for (const AudioHalCapCriterionType& criterionType : capCfg.criterionTypes) {
+ EXPECT_NO_FATAL_FAILURE(ValidateAudioHalCapCriterionType(criterionType));
+ EXPECT_TRUE(criterionTypeMap.insert({criterionType.name, criterionType}).second);
+ }
+ std::unordered_set<std::string> criterionNameSet;
+ for (const AudioHalCapCriterion& criterion : capCfg.criteria) {
+ EXPECT_TRUE(criterionNameSet.insert(criterion.name).second);
+ EXPECT_EQ(criterionTypeMap.count(criterion.criterionTypeName), 1UL);
+ EXPECT_NO_FATAL_FAILURE(ValidateAudioHalCapCriterion(
+ criterion, criterionTypeMap.at(criterion.criterionTypeName)));
+ }
+ EXPECT_EQ(criterionTypeMap.size(), criterionNameSet.size());
+ }
+
+ /**
+ * Verify VolumeGroups are non-empty.
+ * Verify defaultProductStrategyId matches one of the provided productStrategies.
+ * Otherwise, must be left uninitialized.
+ * Verify each volumeGroup has a unique name.
+ * Verify each productStrategy has a unique id.
+ * Verify each volumeGroup is used in a product strategy.
+ * CAP engine: verify productStrategies are non-empty.
+ * Validate contained types.
+ */
+ void ValidateAudioHalEngineConfig() {
+ EXPECT_NE(mEngineConfig->volumeGroups.size(), 0UL);
+ std::unordered_map<std::string, const AudioHalVolumeGroup&> volumeGroupMap;
+ for (const AudioHalVolumeGroup& volumeGroup : mEngineConfig->volumeGroups) {
+ EXPECT_TRUE(volumeGroupMap.insert({volumeGroup.name, volumeGroup}).second);
+ EXPECT_NO_FATAL_FAILURE(ValidateAudioHalVolumeGroup(volumeGroup));
+ }
+ if (!mEngineConfig->productStrategies.empty()) {
+ std::unordered_set<int> productStrategyIdSet;
+ std::unordered_set<std::string> volumeGroupsUsedInStrategies;
+ for (const AudioHalProductStrategy& strategy : mEngineConfig->productStrategies) {
+ EXPECT_TRUE(productStrategyIdSet.insert(strategy.id).second);
+ EXPECT_NO_FATAL_FAILURE(ValidateAudioHalProductStrategy(
+ strategy, volumeGroupMap, volumeGroupsUsedInStrategies));
+ }
+ EXPECT_TRUE(productStrategyIdSet.count(mEngineConfig->defaultProductStrategyId))
+ << "defaultProductStrategyId doesn't match any of the provided "
+ "productStrategies";
+ EXPECT_EQ(volumeGroupMap.size(), volumeGroupsUsedInStrategies.size());
+ } else {
+ EXPECT_EQ(mEngineConfig->defaultProductStrategyId,
+ static_cast<int>(AudioProductStrategyType::SYS_RESERVED_NONE))
+ << "defaultProductStrategyId defined, but no productStrategies were provided";
+ }
+ if (mEngineConfig->capSpecificConfig) {
+ EXPECT_NO_FATAL_FAILURE(
+ ValidateCapSpecificConfig(mEngineConfig->capSpecificConfig.value()));
+ EXPECT_FALSE(mEngineConfig->productStrategies.empty());
+ }
+ }
+
+ private:
+ std::shared_ptr<IConfig> mConfig;
+ std::unique_ptr<AudioHalEngineConfig> mEngineConfig;
+ AudioHalBinderServiceUtil mBinderUtil;
+};
+
+TEST_P(AudioCoreConfig, Published) {
+ // SetUp must complete with no failures.
+}
+
+TEST_P(AudioCoreConfig, CanBeRestarted) {
+ ASSERT_NO_FATAL_FAILURE(RestartService());
+}
+
+TEST_P(AudioCoreConfig, GetEngineConfigIsValid) {
+ ASSERT_NO_FATAL_FAILURE(SetUpEngineConfig());
+ EXPECT_NO_FATAL_FAILURE(ValidateAudioHalEngineConfig());
+}
+
+INSTANTIATE_TEST_SUITE_P(AudioCoreConfigTest, AudioCoreConfig,
+ testing::ValuesIn(android::getAidlHalInstanceNames(IConfig::descriptor)),
+ android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioCoreConfig);
diff --git a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
similarity index 98%
rename from audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
rename to audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index c0c04f4..eb7a3e4 100644
--- a/audio/aidl/vts/VtsHalAudioCoreTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -27,7 +27,7 @@
#include <variant>
#include <vector>
-#define LOG_TAG "VtsHalAudioCore"
+#define LOG_TAG "VtsHalAudioCore.Module"
#include <android-base/logging.h>
#include <StreamWorker.h>
@@ -490,16 +490,16 @@
private:
StreamDescriptor::State getState() const { return mSteps[mCurrentStep].second; }
bool isBurstBifurcation() {
- return getTrigger() == TransitionTrigger{kBurstCommand}&& getState() ==
- StreamDescriptor::State::TRANSFERRING;
+ return getTrigger() == TransitionTrigger{kBurstCommand} &&
+ getState() == StreamDescriptor::State::TRANSFERRING;
}
bool isPauseBifurcation() {
- return getTrigger() == TransitionTrigger{kPauseCommand}&& getState() ==
- StreamDescriptor::State::TRANSFER_PAUSED;
+ return getTrigger() == TransitionTrigger{kPauseCommand} &&
+ getState() == StreamDescriptor::State::TRANSFER_PAUSED;
}
bool isStartBifurcation() {
- return getTrigger() == TransitionTrigger{kStartCommand}&& getState() ==
- StreamDescriptor::State::TRANSFERRING;
+ return getTrigger() == TransitionTrigger{kStartCommand} &&
+ getState() == StreamDescriptor::State::TRANSFERRING;
}
const std::vector<StateTransition> mSteps;
size_t mCurrentStep = 0;
@@ -1902,9 +1902,13 @@
using AudioStreamIn = AudioStream<IStreamIn>;
using AudioStreamOut = AudioStream<IStreamOut>;
-#define TEST_IN_AND_OUT_STREAM(method_name) \
- TEST_P(AudioStreamIn, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); } \
- TEST_P(AudioStreamOut, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); }
+#define TEST_IN_AND_OUT_STREAM(method_name) \
+ TEST_P(AudioStreamIn, method_name) { \
+ ASSERT_NO_FATAL_FAILURE(method_name()); \
+ } \
+ TEST_P(AudioStreamOut, method_name) { \
+ ASSERT_NO_FATAL_FAILURE(method_name()); \
+ }
TEST_IN_AND_OUT_STREAM(CloseTwice);
TEST_IN_AND_OUT_STREAM(OpenAllConfigs);
@@ -2280,9 +2284,13 @@
using AudioStreamIoIn = AudioStreamIo<IStreamIn>;
using AudioStreamIoOut = AudioStreamIo<IStreamOut>;
-#define TEST_IN_AND_OUT_STREAM_IO(method_name) \
- TEST_P(AudioStreamIoIn, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); } \
- TEST_P(AudioStreamIoOut, method_name) { ASSERT_NO_FATAL_FAILURE(method_name()); }
+#define TEST_IN_AND_OUT_STREAM_IO(method_name) \
+ TEST_P(AudioStreamIoIn, method_name) { \
+ ASSERT_NO_FATAL_FAILURE(method_name()); \
+ } \
+ TEST_P(AudioStreamIoOut, method_name) { \
+ ASSERT_NO_FATAL_FAILURE(method_name()); \
+ }
TEST_IN_AND_OUT_STREAM_IO(Run);
@@ -2435,9 +2443,13 @@
// Not all tests require both directions, so parametrization would require
// more abstractions.
-#define TEST_PATCH_BOTH_DIRECTIONS(method_name) \
- TEST_P(AudioModulePatch, method_name##Input) { ASSERT_NO_FATAL_FAILURE(method_name(true)); } \
- TEST_P(AudioModulePatch, method_name##Output) { ASSERT_NO_FATAL_FAILURE(method_name(false)); }
+#define TEST_PATCH_BOTH_DIRECTIONS(method_name) \
+ TEST_P(AudioModulePatch, method_name##Input) { \
+ ASSERT_NO_FATAL_FAILURE(method_name(true)); \
+ } \
+ TEST_P(AudioModulePatch, method_name##Output) { \
+ ASSERT_NO_FATAL_FAILURE(method_name(false)); \
+ }
TEST_PATCH_BOTH_DIRECTIONS(ResetPortConfigUsedByPatch);
TEST_PATCH_BOTH_DIRECTIONS(SetInvalidPatch);
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
index 8212149..4f14bf0 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -752,16 +752,9 @@
::testing::Combine(testing::ValuesIn(
EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor))),
[](const testing::TestParamInfo<AudioEffectTest::ParamType>& info) {
- auto msSinceEpoch = std::chrono::duration_cast<std::chrono::nanoseconds>(
- std::chrono::system_clock::now().time_since_epoch())
- .count();
auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
- std::ostringstream address;
- address << msSinceEpoch << "_factory_" << instance.first.get();
- std::string name = address.str() + "_UUID_timeLow_" +
- ::android::internal::ToString(instance.second.uuid.timeLow) +
- "_timeMid_" +
- ::android::internal::ToString(instance.second.uuid.timeMid);
+ std::string name = "TYPE_" + instance.second.type.toString() + "_UUID_" +
+ instance.second.uuid.toString();
std::replace_if(
name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
return name;
diff --git a/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
new file mode 100644
index 0000000..7adf63c
--- /dev/null
+++ b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsHalBassBoostTest"
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include <limits.h>
+
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::BassBoost;
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kBassBoostTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_STRENGTH };
+using BassBoostParamTestParam =
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>, int>;
+
+/*
+ * Testing parameter range, assuming the parameter supported by effect is in this range.
+ * Parameter should be within the valid range defined in the documentation,
+ * for any supported value test expects EX_NONE from IEffect.setParameter(),
+ * otherwise expect EX_ILLEGAL_ARGUMENT.
+ */
+
+const std::vector<int> kStrengthValues = {
+ std::numeric_limits<int>::min(),
+ BassBoost::MIN_PER_MILLE_STRENGTH - 1,
+ BassBoost::MIN_PER_MILLE_STRENGTH,
+ (BassBoost::MIN_PER_MILLE_STRENGTH + BassBoost::MAX_PER_MILLE_STRENGTH) >> 1,
+ BassBoost::MAX_PER_MILLE_STRENGTH,
+ BassBoost::MAX_PER_MILLE_STRENGTH + 2,
+ std::numeric_limits<int>::max()};
+
+class BassBoostParamTest : public ::testing::TestWithParam<BassBoostParamTestParam>,
+ public EffectHelper {
+ public:
+ BassBoostParamTest() : mParamStrength(std::get<PARAM_STRENGTH>(GetParam())) {
+ std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+ }
+
+ void SetUp() override {
+ ASSERT_NE(nullptr, mFactory);
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mIdentity));
+
+ Parameter::Specific specific = getDefaultParamSpecific();
+ Parameter::Common common = EffectHelper::createParamCommon(
+ 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+ kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+ IEffect::OpenEffectReturn ret;
+ ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+ ASSERT_NE(nullptr, mEffect);
+ }
+
+ void TearDown() override {
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+ }
+
+ Parameter::Specific getDefaultParamSpecific() {
+ BassBoost bb = BassBoost::make<BassBoost::strengthPm>(BassBoost::MIN_PER_MILLE_STRENGTH);
+ Parameter::Specific specific =
+ Parameter::Specific::make<Parameter::Specific::bassBoost>(bb);
+ return specific;
+ }
+
+ static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+ std::shared_ptr<IFactory> mFactory;
+ std::shared_ptr<IEffect> mEffect;
+ Descriptor::Identity mIdentity;
+ int mParamStrength = BassBoost::MIN_PER_MILLE_STRENGTH;
+
+ void SetAndGetBassBoostParameters() {
+ for (auto& it : mTags) {
+ auto& tag = it.first;
+ auto& bb = it.second;
+
+ // validate parameter
+ Descriptor desc;
+ ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+ const bool valid = isTagInRange(it.first, it.second, desc);
+ const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+ // set parameter
+ Parameter expectParam;
+ Parameter::Specific specific;
+ specific.set<Parameter::Specific::bassBoost>(bb);
+ expectParam.set<Parameter::specific>(specific);
+ EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+ // only get if parameter in range and set success
+ if (expected == EX_NONE) {
+ Parameter getParam;
+ Parameter::Id id;
+ BassBoost::Id bbId;
+ bbId.set<BassBoost::Id::commonTag>(tag);
+ id.set<Parameter::Id::bassBoostTag>(bbId);
+ // if set success, then get should match
+ EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+ EXPECT_EQ(expectParam, getParam);
+ }
+ }
+ }
+
+ void addStrengthParam(int strength) {
+ BassBoost bb;
+ bb.set<BassBoost::strengthPm>(strength);
+ mTags.push_back({BassBoost::strengthPm, bb});
+ }
+
+ bool isTagInRange(const BassBoost::Tag& tag, const BassBoost& bb,
+ const Descriptor& desc) const {
+ const BassBoost::Capability& bbCap = desc.capability.get<Capability::bassBoost>();
+ switch (tag) {
+ case BassBoost::strengthPm: {
+ int strength = bb.get<BassBoost::strengthPm>();
+ return isStrengthInRange(bbCap, strength);
+ }
+ default:
+ return false;
+ }
+ return false;
+ }
+
+ bool isStrengthInRange(const BassBoost::Capability& cap, int strength) const {
+ return cap.strengthSupported && strength >= BassBoost::MIN_PER_MILLE_STRENGTH &&
+ strength <= BassBoost::MAX_PER_MILLE_STRENGTH;
+ }
+
+ private:
+ std::vector<std::pair<BassBoost::Tag, BassBoost>> mTags;
+ void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(BassBoostParamTest, SetAndGetStrength) {
+ EXPECT_NO_FATAL_FAILURE(addStrengthParam(mParamStrength));
+ SetAndGetBassBoostParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ BassBoostTest, BassBoostParamTest,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kBassBoostTypeUUID)),
+ testing::ValuesIn(kStrengthValues)),
+ [](const testing::TestParamInfo<BassBoostParamTest::ParamType>& info) {
+ auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
+ std::string strength = std::to_string(std::get<PARAM_STRENGTH>(info.param));
+ std::string name = instance.second.uuid.toString() + "_strength_" + strength;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BassBoostParamTest);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
index f19dff6..1b147a6 100644
--- a/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
@@ -327,18 +327,9 @@
IFactory::descriptor, kEqualizerTypeUUID)),
testing::ValuesIn(kBandLevels)),
[](const testing::TestParamInfo<EqualizerTest::ParamType>& info) {
- auto msSinceEpoch = std::chrono::duration_cast<std::chrono::nanoseconds>(
- std::chrono::system_clock::now().time_since_epoch())
- .count();
auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
std::string bandLevel = std::to_string(std::get<PARAM_BAND_LEVEL>(info.param));
- std::ostringstream address;
- address << msSinceEpoch << "_factory_" << instance.first.get();
- std::string name = address.str() + "_UUID_timeLow_" +
- ::android::internal::ToString(instance.second.uuid.timeLow) +
- "_timeMid_" +
- ::android::internal::ToString(instance.second.uuid.timeMid) +
- "_bandLevel_" + bandLevel;
+ std::string name = instance.second.uuid.toString() + "_bandLevel_" + bandLevel;
std::replace_if(
name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
return name;
diff --git a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
index 1485657..3fd2812 100644
--- a/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalLoudnessEnhancerTargetTest.cpp
@@ -15,6 +15,7 @@
*/
#include <aidl/Vintf.h>
+#include <string>
#define LOG_TAG "VtsHalLoudnessEnhancerTest"
@@ -129,19 +130,9 @@
IFactory::descriptor, kLoudnessEnhancerTypeUUID)),
testing::ValuesIn(kGainMbValues)),
[](const testing::TestParamInfo<LoudnessEnhancerParamTest::ParamType>& info) {
- auto msSinceEpoch = std::chrono::duration_cast<std::chrono::nanoseconds>(
- std::chrono::system_clock::now().time_since_epoch())
- .count();
auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
std::string gainMb = std::to_string(std::get<PARAM_GAIN_MB>(info.param));
-
- std::ostringstream address;
- address << msSinceEpoch << "_factory_" << instance.first.get();
- std::string name = address.str() + "_UUID_timeLow_" +
- ::android::internal::ToString(instance.second.uuid.timeLow) +
- "_timeMid_" +
- ::android::internal::ToString(instance.second.uuid.timeMid) +
- "_gainMb" + gainMb;
+ std::string name = instance.second.uuid.toString() + "_gainMb_" + gainMb;
std::replace_if(
name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
return name;
diff --git a/automotive/vehicle/aidl/Android.bp b/automotive/vehicle/aidl/Android.bp
index 9aeb4d2..18a5046 100644
--- a/automotive/vehicle/aidl/Android.bp
+++ b/automotive/vehicle/aidl/Android.bp
@@ -27,6 +27,7 @@
srcs: [
"android/hardware/automotive/vehicle/**/*.aidl",
],
+ frozen: false,
stability: "vintf",
backend: {
cpp: {
diff --git a/biometrics/common/aidl/Android.bp b/biometrics/common/aidl/Android.bp
index 3cd76fd..88edf04 100644
--- a/biometrics/common/aidl/Android.bp
+++ b/biometrics/common/aidl/Android.bp
@@ -13,6 +13,7 @@
srcs: [
"android/hardware/biometrics/common/*.aidl",
],
+ frozen: false,
stability: "vintf",
backend: {
java: {
diff --git a/camera/common/aidl/Android.bp b/camera/common/aidl/Android.bp
index e1c9cc5..4ffcfd9 100644
--- a/camera/common/aidl/Android.bp
+++ b/camera/common/aidl/Android.bp
@@ -11,6 +11,7 @@
name: "android.hardware.camera.common",
vendor_available: true,
srcs: ["android/hardware/camera/common/*.aidl"],
+ frozen: true,
stability: "vintf",
backend: {
cpp: {
diff --git a/camera/device/aidl/Android.bp b/camera/device/aidl/Android.bp
index 2e5b667..bf5bf63 100644
--- a/camera/device/aidl/Android.bp
+++ b/camera/device/aidl/Android.bp
@@ -11,6 +11,7 @@
name: "android.hardware.camera.device",
vendor_available: true,
srcs: ["android/hardware/camera/device/*.aidl"],
+ frozen: false,
stability: "vintf",
imports: [
"android.hardware.common-V2",
diff --git a/camera/metadata/aidl/Android.bp b/camera/metadata/aidl/Android.bp
index 0113a4b..7bec61d 100644
--- a/camera/metadata/aidl/Android.bp
+++ b/camera/metadata/aidl/Android.bp
@@ -11,6 +11,7 @@
name: "android.hardware.camera.metadata",
vendor_available: true,
srcs: ["android/hardware/camera/metadata/*.aidl"],
+ frozen: false,
stability: "vintf",
backend: {
cpp: {
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 9f43219..b87b1a6 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -577,6 +577,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.sensors</name>
+ <version>2</version>
<interface>
<name>ISensors</name>
<instance>default</instance>
@@ -707,14 +708,6 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.wifi</name>
- <version>1.3-6</version>
- <interface>
- <name>IWifi</name>
- <instance>default</instance>
- </interface>
- </hal>
<hal format="aidl" optional="true">
<name>android.hardware.uwb</name>
<version>1</version>
diff --git a/graphics/composer/2.2/utils/vts/ComposerVts.cpp b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
index b706596..a6dfcaf 100644
--- a/graphics/composer/2.2/utils/vts/ComposerVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ComposerVts.cpp
@@ -126,15 +126,23 @@
ASSERT_EQ(Error::NONE, error) << "failed to setReadbackBuffer";
}
-void ComposerClient::getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
- Dataspace* outDataspace) {
+void ComposerClient::getRequiredReadbackBufferAttributes(Display display,
+ PixelFormat* outPixelFormat,
+ Dataspace* outDataspace) {
+ ASSERT_EQ(Error::NONE, getReadbackBufferAttributes(display, outPixelFormat, outDataspace));
+}
+
+Error ComposerClient::getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
+ Dataspace* outDataspace) {
+ Error error;
mClient->getReadbackBufferAttributes(
- display,
- [&](const auto& tmpError, const auto& tmpOutPixelFormat, const auto& tmpOutDataspace) {
- ASSERT_EQ(Error::NONE, tmpError) << "failed to get readback buffer attributes";
- *outPixelFormat = tmpOutPixelFormat;
- *outDataspace = tmpOutDataspace;
- });
+ display, [&](const Error& tmpError, const PixelFormat& tmpPixelFormat,
+ const Dataspace& tmpDataspace) {
+ error = tmpError;
+ *outPixelFormat = tmpPixelFormat;
+ *outDataspace = tmpDataspace;
+ });
+ return error;
}
void ComposerClient::getReadbackBufferFence(Display display, int32_t* outFence) {
diff --git a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
index a1794af..5dd68df 100644
--- a/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
+++ b/graphics/composer/2.2/utils/vts/ReadbackVts.cpp
@@ -19,6 +19,8 @@
#include "renderengine/ExternalTexture.h"
#include "renderengine/impl/ExternalTexture.h"
+using ::android::status_t;
+
namespace android {
namespace hardware {
namespace graphics {
@@ -107,6 +109,40 @@
}
}
+void ReadbackHelper::fillBufferAndGetFence(const sp<GraphicBuffer>& graphicBuffer,
+ IComposerClient::Color desiredColor, int* fillFence) {
+ ASSERT_NE(nullptr, fillFence);
+ std::vector<IComposerClient::Color> desiredColors(
+ static_cast<size_t>(graphicBuffer->getWidth() * graphicBuffer->getHeight()));
+ ::android::Rect bounds = graphicBuffer->getBounds();
+ fillColorsArea(desiredColors, static_cast<int32_t>(graphicBuffer->getWidth()),
+ {bounds.left, bounds.top, bounds.right, bounds.bottom}, desiredColor);
+ ASSERT_NO_FATAL_FAILURE(fillBufferAndGetFence(graphicBuffer, desiredColors, fillFence));
+}
+
+void ReadbackHelper::fillBufferAndGetFence(const sp<GraphicBuffer>& graphicBuffer,
+ const std::vector<IComposerClient::Color>& desiredColors,
+ int* fillFence) {
+ ASSERT_TRUE(graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGB_888 ||
+ graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGBA_8888);
+ void* bufData;
+ int32_t bytesPerPixel = -1;
+ int32_t bytesPerStride = -1;
+ status_t status =
+ graphicBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ &bufData, &bytesPerPixel, &bytesPerStride);
+ ASSERT_EQ(::android::OK, status);
+
+ const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
+ ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
+ : graphicBuffer->getStride();
+ ReadbackHelper::fillBuffer(graphicBuffer->getWidth(), graphicBuffer->getHeight(), stride,
+ bufData, static_cast<PixelFormat>(graphicBuffer->getPixelFormat()),
+ desiredColors);
+ status = graphicBuffer->unlockAsync(fillFence);
+ ASSERT_EQ(::android::OK, status);
+}
+
void ReadbackHelper::fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData,
PixelFormat pixelFormat,
std::vector<IComposerClient::Color> desiredPixelColors) {
@@ -116,16 +152,16 @@
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
int pixel = row * width + col;
- IComposerClient::Color srcColor = desiredPixelColors[pixel];
+ IComposerClient::Color desiredColor = desiredPixelColors[pixel];
int offset = (row * stride + col) * bytesPerPixel;
uint8_t* pixelColor = (uint8_t*)bufferData + offset;
- pixelColor[0] = srcColor.r;
- pixelColor[1] = srcColor.g;
- pixelColor[2] = srcColor.b;
+ pixelColor[0] = desiredColor.r;
+ pixelColor[1] = desiredColor.g;
+ pixelColor[2] = desiredColor.b;
if (bytesPerPixel == 4) {
- pixelColor[3] = srcColor.a;
+ pixelColor[3] = desiredColor.a;
}
}
}
@@ -152,12 +188,14 @@
}
}
-bool ReadbackHelper::readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace,
- const Error error) {
+bool ReadbackHelper::readbackSupported(PixelFormat pixelFormat, Dataspace dataspace, Error error) {
if (error != Error::NONE) {
return false;
}
- // TODO: add support for RGBA_1010102
+ return readbackSupported(pixelFormat, dataspace);
+}
+
+bool ReadbackHelper::readbackSupported(PixelFormat pixelFormat, Dataspace dataspace) {
if (pixelFormat != PixelFormat::RGB_888 && pixelFormat != PixelFormat::RGBA_8888) {
return false;
}
@@ -167,71 +205,94 @@
return true;
}
-void ReadbackHelper::compareColorBuffers(std::vector<IComposerClient::Color>& expectedColors,
- void* bufferData, const uint32_t stride,
- const uint32_t width, const uint32_t height,
- const PixelFormat pixelFormat) {
- const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
- ASSERT_NE(-1, bytesPerPixel);
- for (int row = 0; row < height; row++) {
- for (int col = 0; col < width; col++) {
- int pixel = row * width + col;
- int offset = (row * stride + col) * bytesPerPixel;
- uint8_t* pixelColor = (uint8_t*)bufferData + offset;
+void ReadbackHelper::createReadbackBuffer(uint32_t width, uint32_t height, PixelFormat pixelFormat,
+ Dataspace dataspace, sp<GraphicBuffer>* graphicBuffer) {
+ ASSERT_NE(nullptr, graphicBuffer);
+ if (!readbackSupported(pixelFormat, dataspace)) {
+ *graphicBuffer = nullptr;
+ }
+ android::PixelFormat bufferFormat = static_cast<android::PixelFormat>(pixelFormat);
+ uint32_t layerCount = 1;
+ uint64_t usage = static_cast<uint64_t>(static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN) |
+ static_cast<uint64_t>(BufferUsage::GPU_TEXTURE));
+ *graphicBuffer = sp<GraphicBuffer>::make(width, height, bufferFormat, layerCount, usage,
+ "ReadbackBuffer");
+ ASSERT_NE(nullptr, *graphicBuffer);
+ ASSERT_EQ(::android::OK, (*graphicBuffer)->initCheck());
+}
- ASSERT_EQ(expectedColors[pixel].r, pixelColor[0]);
- ASSERT_EQ(expectedColors[pixel].g, pixelColor[1]);
- ASSERT_EQ(expectedColors[pixel].b, pixelColor[2]);
+void ReadbackHelper::compareColorToBuffer(IComposerClient::Color expectedColor,
+ const sp<GraphicBuffer>& graphicBuffer, int32_t fence) {
+ std::vector<IComposerClient::Color> expectedColors(
+ static_cast<size_t>(graphicBuffer->getWidth() * graphicBuffer->getHeight()));
+ ::android::Rect bounds = graphicBuffer->getBounds();
+ fillColorsArea(expectedColors, static_cast<int32_t>(graphicBuffer->getWidth()),
+ {bounds.left, bounds.top, bounds.right, bounds.bottom}, expectedColor);
+ compareColorsToBuffer(expectedColors, graphicBuffer, fence);
+}
+
+void ReadbackHelper::compareColorsToBuffer(std::vector<IComposerClient::Color>& expectedColors,
+ const sp<GraphicBuffer>& graphicBuffer, int32_t fence) {
+ ASSERT_TRUE(graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGB_888 ||
+ graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGBA_8888);
+
+ int bytesPerPixel = -1;
+ int bytesPerStride = -1;
+ void* bufData = nullptr;
+ status_t status = graphicBuffer->lockAsync(GRALLOC_USAGE_SW_READ_OFTEN, &bufData, fence,
+ &bytesPerPixel, &bytesPerStride);
+ ASSERT_EQ(::android::OK, status);
+
+ const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
+ ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
+ : graphicBuffer->getStride();
+
+ if (bytesPerPixel == -1) {
+ PixelFormat pixelFormat = static_cast<PixelFormat>(graphicBuffer->getPixelFormat());
+ bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
+ }
+ ASSERT_NE(-1, bytesPerPixel);
+ for (int row = 0; row < graphicBuffer->getHeight(); row++) {
+ for (int col = 0; col < graphicBuffer->getWidth(); col++) {
+ int pixel = row * static_cast<int32_t>(graphicBuffer->getWidth()) + col;
+ int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
+ uint8_t* pixelColor = (uint8_t*)bufData + offset;
+ const IComposerClient::Color expectedColor = expectedColors[static_cast<size_t>(pixel)];
+ ASSERT_EQ(std::round(255.0f * expectedColor.r), pixelColor[0]);
+ ASSERT_EQ(std::round(255.0f * expectedColor.g), pixelColor[1]);
+ ASSERT_EQ(std::round(255.0f * expectedColor.b), pixelColor[2]);
}
}
+
+ status = graphicBuffer->unlock();
+ ASSERT_EQ(::android::OK, status);
}
ReadbackBuffer::ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client,
- const std::shared_ptr<Gralloc>& gralloc, uint32_t width,
- uint32_t height, PixelFormat pixelFormat, Dataspace dataspace) {
+ uint32_t width, uint32_t height, PixelFormat pixelFormat) {
mDisplay = display;
-
mComposerClient = client;
- mGralloc = gralloc;
-
- mPixelFormat = pixelFormat;
- mDataspace = dataspace;
-
mWidth = width;
mHeight = height;
+ mPixelFormat = pixelFormat;
mLayerCount = 1;
- mFormat = mPixelFormat;
mUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::GPU_TEXTURE);
-
- mAccessRegion.top = 0;
- mAccessRegion.left = 0;
- mAccessRegion.width = width;
- mAccessRegion.height = height;
}
void ReadbackBuffer::setReadbackBuffer() {
- mBufferHandle.reset(new Gralloc::NativeHandleWrapper(
- mGralloc->allocate(mWidth, mHeight, mLayerCount, mFormat, mUsage,
- /*import*/ true, &mStride)));
- ASSERT_NE(false, mGralloc->validateBufferSize(mBufferHandle->get(), mWidth, mHeight,
- mLayerCount, mFormat, mUsage, mStride));
- ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(mDisplay, mBufferHandle->get(), -1));
+ mGraphicBuffer = sp<GraphicBuffer>::make(mWidth, mHeight,
+ static_cast<::android::PixelFormat>(mPixelFormat),
+ mLayerCount, mUsage, "ReadbackBuffer");
+ ASSERT_NE(nullptr, mGraphicBuffer);
+ ASSERT_EQ(::android::OK, mGraphicBuffer->initCheck());
+ mComposerClient->setReadbackBuffer(mDisplay, mGraphicBuffer->handle, -1 /* fence */);
}
void ReadbackBuffer::checkReadbackBuffer(std::vector<IComposerClient::Color> expectedColors) {
// lock buffer for reading
int32_t fenceHandle;
ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mDisplay, &fenceHandle));
-
- void* bufData = mGralloc->lock(mBufferHandle->get(), mUsage, mAccessRegion, fenceHandle);
- ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888);
- ReadbackHelper::compareColorBuffers(expectedColors, bufData, mStride, mWidth, mHeight,
- mPixelFormat);
- int32_t unlockFence = mGralloc->unlock(mBufferHandle->get());
- if (unlockFence != -1) {
- sync_wait(unlockFence, -1);
- close(unlockFence);
- }
+ ReadbackHelper::compareColorsToBuffer(expectedColors, mGraphicBuffer, fenceHandle);
}
void TestColorLayer::write(const std::shared_ptr<CommandWriterBase>& writer) {
diff --git a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
index 1700b2a..254ff3b 100644
--- a/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
+++ b/graphics/composer/2.2/utils/vts/RenderEngineVts.cpp
@@ -83,9 +83,7 @@
void TestRenderEngine::checkColorBuffer(std::vector<V2_2::IComposerClient::Color>& expectedColors) {
void* bufferData;
ASSERT_EQ(0, mGraphicBuffer->lock(mGraphicBuffer->getUsage(), &bufferData));
- ReadbackHelper::compareColorBuffers(expectedColors, bufferData, mGraphicBuffer->getStride(),
- mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(),
- mFormat);
+ ReadbackHelper::compareColorsToBuffer(expectedColors, mGraphicBuffer, -1 /* fence */);
ASSERT_EQ(0, mGraphicBuffer->unlock());
}
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
index 02d7bdb..bbf8ef3 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ComposerVts.h
@@ -78,8 +78,10 @@
PixelFormat format, Dataspace dataspace);
void setPowerMode_2_2(Display display, IComposerClient::PowerMode mode);
void setReadbackBuffer(Display display, const native_handle_t* buffer, int32_t releaseFence);
- void getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
- Dataspace* outDataspace);
+ void getRequiredReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
+ Dataspace* outDataspace);
+ Error getReadbackBufferAttributes(Display display, PixelFormat* outPixelFormat,
+ Dataspace* outDataspace);
void getReadbackBufferFence(Display display, int32_t* outFence);
std::vector<ColorMode> getColorModes(Display display);
diff --git a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
index 58efde9..7100297 100644
--- a/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
+++ b/graphics/composer/2.2/utils/vts/include/composer-vts/2.2/ReadbackVts.h
@@ -34,6 +34,8 @@
namespace V2_2 {
namespace vts {
+using android::GraphicBuffer;
+using android::sp;
using android::hardware::hidl_handle;
using common::V1_1::BufferUsage;
using common::V1_1::Dataspace;
@@ -156,6 +158,13 @@
static int32_t GetBytesPerPixel(PixelFormat pixelFormat);
+ static void fillBufferAndGetFence(const sp<GraphicBuffer>& graphicBuffer,
+ IComposerClient::Color desiredColor, int* fillFence);
+
+ static void fillBufferAndGetFence(const sp<GraphicBuffer>& graphicBuffer,
+ const std::vector<IComposerClient::Color>& desiredColors,
+ int* fillFence);
+
static void fillBuffer(int32_t width, int32_t height, uint32_t stride, void* bufferData,
PixelFormat pixelFormat,
std::vector<IComposerClient::Color> desiredPixelColors);
@@ -166,40 +175,39 @@
static void fillColorsArea(std::vector<IComposerClient::Color>& expectedColors, int32_t stride,
IComposerClient::Rect area, IComposerClient::Color color);
- static bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace,
- const Error error);
-
static const std::vector<ColorMode> colorModes;
static const std::vector<Dataspace> dataspaces;
- static void compareColorBuffers(std::vector<IComposerClient::Color>& expectedColors,
- void* bufferData, const uint32_t stride, const uint32_t width,
- const uint32_t height, const PixelFormat pixelFormat);
+ static bool readbackSupported(PixelFormat pixelFormat, Dataspace dataspace, Error error);
+ static bool readbackSupported(PixelFormat pixelFormat, Dataspace dataspace);
+
+ static void createReadbackBuffer(uint32_t width, uint32_t height, PixelFormat pixelFormat,
+ Dataspace dataspace, sp<GraphicBuffer>* graphicBuffer);
+
+ static void compareColorToBuffer(IComposerClient::Color expectedColors,
+ const sp<GraphicBuffer>& graphicBuffer, int32_t fence);
+
+ static void compareColorsToBuffer(std::vector<IComposerClient::Color>& expectedColors,
+ const sp<GraphicBuffer>& graphicBuffer, int32_t fence);
};
class ReadbackBuffer {
public:
- ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client,
- const std::shared_ptr<Gralloc>& gralloc, uint32_t width, uint32_t height,
- PixelFormat pixelFormat, Dataspace dataspace);
+ ReadbackBuffer(Display display, const std::shared_ptr<ComposerClient>& client, uint32_t width,
+ uint32_t height, PixelFormat pixelFormat);
void setReadbackBuffer();
void checkReadbackBuffer(std::vector<IComposerClient::Color> expectedColors);
protected:
+ sp<GraphicBuffer> mGraphicBuffer;
uint32_t mWidth;
uint32_t mHeight;
- uint32_t mLayerCount;
- PixelFormat mFormat;
- uint64_t mUsage;
- AccessRegion mAccessRegion;
- uint32_t mStride;
- std::unique_ptr<Gralloc::NativeHandleWrapper> mBufferHandle = nullptr;
PixelFormat mPixelFormat;
- Dataspace mDataspace;
+ uint32_t mLayerCount;
+ uint64_t mUsage;
Display mDisplay;
- std::shared_ptr<Gralloc> mGralloc;
std::shared_ptr<ComposerClient> mComposerClient;
};
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
index e2a0f4d..5b8ce3f 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
@@ -40,7 +40,6 @@
namespace {
using android::Rect;
-using common::V1_1::BufferUsage;
using common::V1_1::Dataspace;
using common::V1_1::PixelFormat;
using V2_1::Config;
@@ -100,8 +99,8 @@
mTestRenderEngine->initGraphicBuffer(
static_cast<uint32_t>(mDisplayWidth), static_cast<uint32_t>(mDisplayHeight), 1,
- static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::GPU_RENDER_TARGET));
+ GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_HW_RENDER);
mTestRenderEngine->setDisplaySettings(clientCompositionDisplay);
}
@@ -116,6 +115,22 @@
}
}
+ sp<GraphicBuffer> allocateBuffer(uint32_t width, uint32_t height, uint32_t usage) {
+ const auto& graphicBuffer = sp<GraphicBuffer>::make(
+ width, height, android::PIXEL_FORMAT_RGBA_8888,
+ /*layerCount*/ 1u, usage, "VtsHalGraphicsComposer2_2_ReadbackTest");
+
+ if (graphicBuffer && android::OK == graphicBuffer->initCheck()) {
+ return nullptr;
+ }
+ return graphicBuffer;
+ }
+
+ sp<GraphicBuffer> allocateBuffer(uint32_t usage) {
+ return allocateBuffer(static_cast<uint32_t>(mDisplayWidth),
+ static_cast<uint32_t>(mDisplayHeight), usage);
+ }
+
void clearCommandReaderState() {
mReader->mCompositionChanges.clear();
mReader->mErrors.clear();
@@ -193,15 +208,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -220,8 +229,8 @@
std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
@@ -255,15 +264,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -272,8 +275,8 @@
mWriter->selectDisplay(mPrimaryDisplay);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
@@ -319,6 +322,155 @@
}
}
+TEST_P(GraphicsCompositionTest, SetLayerBufferWithSlotsToClear) {
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ if (error == Error::UNSUPPORTED) {
+ GTEST_SUCCEED() << "Readback is unsupported";
+ return;
+ }
+ ASSERT_EQ(Error::NONE, error);
+
+ sp<GraphicBuffer> readbackBuffer;
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::createReadbackBuffer(
+ mDisplayWidth, mDisplayHeight, mPixelFormat, mDataspace, &readbackBuffer));
+ if (readbackBuffer == nullptr) {
+ GTEST_SUCCEED() << "Unsupported readback buffer attributes";
+ return;
+ }
+ // no fence needed for the readback buffer
+ int noFence = -1;
+
+ sp<GraphicBuffer> clearSlotBuffer = allocateBuffer(1u, 1u, GRALLOC_USAGE_HW_COMPOSER);
+ ASSERT_NE(nullptr, clearSlotBuffer);
+
+ // red buffer
+ uint32_t usage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN;
+ sp<GraphicBuffer> redBuffer = allocateBuffer(usage);
+ ASSERT_NE(nullptr, redBuffer);
+ int redFence;
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(redBuffer, RED, &redFence));
+
+ // blue buffer
+ sp<GraphicBuffer> blueBuffer = allocateBuffer(usage);
+ ASSERT_NE(nullptr, blueBuffer);
+ int blueFence;
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(blueBuffer, BLUE, &blueFence));
+
+ // layer defaults
+ IComposerClient::Rect rectFullDisplay = {0, 0, mDisplayWidth, mDisplayHeight};
+ Layer layer = mComposerClient->createLayer(mPrimaryDisplay, 3);
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerDisplayFrame(rectFullDisplay);
+ mWriter->setLayerCompositionType(IComposerClient::Composition::DEVICE);
+
+ // set the layer to the blue buffer
+ // should be blue
+ {
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(
+ mPrimaryDisplay, readbackBuffer->handle, noFence));
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerBuffer(/*slot*/ 0, blueBuffer->handle, blueFence);
+ mWriter->validateDisplay();
+ execute();
+ ASSERT_TRUE(mReader->mCompositionChanges.empty());
+ ASSERT_TRUE(mReader->mErrors.size());
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->presentDisplay();
+ execute();
+ int32_t fence;
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fence));
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::compareColorToBuffer(BLUE, readbackBuffer, fence));
+ }
+
+ // change the layer to the red buffer
+ // should be red
+ {
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(
+ mPrimaryDisplay, readbackBuffer->handle, noFence));
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerBuffer(/*slot*/ 1, redBuffer->handle, redFence);
+ mWriter->validateDisplay();
+ execute();
+ ASSERT_TRUE(mReader->mCompositionChanges.empty());
+ ASSERT_TRUE(mReader->mErrors.size());
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->presentDisplay();
+ execute();
+ int32_t fence;
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fence));
+ ReadbackHelper::compareColorToBuffer(RED, readbackBuffer, fence);
+ }
+
+ // clear the slot for the blue buffer
+ // should still be red
+ {
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(
+ mPrimaryDisplay, readbackBuffer->handle, noFence));
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerBuffer(/*slot*/ 0, clearSlotBuffer->handle, /*fence*/ -1);
+ mWriter->validateDisplay();
+ execute();
+ ASSERT_TRUE(mReader->mCompositionChanges.empty());
+ ASSERT_TRUE(mReader->mErrors.size());
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->presentDisplay();
+ execute();
+ int32_t fence;
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fence));
+ ReadbackHelper::compareColorToBuffer(RED, readbackBuffer, fence);
+ }
+
+ // clear the slot for the red buffer, and set the buffer with the same slot to the blue buffer
+ // should be blue
+ {
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(
+ mPrimaryDisplay, readbackBuffer->handle, noFence));
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerBuffer(/*slot*/ 1, clearSlotBuffer->handle, /*fence*/ -1);
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerBuffer(/*slot*/ 1, blueBuffer->handle, blueFence);
+ mWriter->validateDisplay();
+ execute();
+ ASSERT_TRUE(mReader->mCompositionChanges.empty());
+ ASSERT_TRUE(mReader->mErrors.size());
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->presentDisplay();
+ execute();
+ int32_t fence;
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fence));
+ ReadbackHelper::compareColorToBuffer(BLUE, readbackBuffer, fence);
+ }
+
+ // clear the slot for the now-blue buffer
+ // should be black (no buffer)
+ // TODO(b/262037933) Ensure we never clear the active buffer's slot with the placeholder buffer
+ // by setting the layer to the color black
+ {
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->setReadbackBuffer(
+ mPrimaryDisplay, readbackBuffer->handle, noFence));
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->selectLayer(layer);
+ mWriter->setLayerBuffer(/*slot*/ 1, clearSlotBuffer->handle, /*fence*/ -1);
+ mWriter->validateDisplay();
+ execute();
+ ASSERT_TRUE(mReader->mCompositionChanges.empty());
+ ASSERT_TRUE(mReader->mErrors.size());
+ mWriter->selectDisplay(mPrimaryDisplay);
+ mWriter->presentDisplay();
+ execute();
+ int32_t fence;
+ ASSERT_NO_FATAL_FAILURE(mComposerClient->getReadbackBufferFence(mPrimaryDisplay, &fence));
+ ReadbackHelper::compareColorToBuffer(BLACK, readbackBuffer, fence);
+ }
+}
+
TEST_P(GraphicsCompositionTest, SetLayerBufferNoEffect) {
for (ColorMode mode : mTestColorModes) {
std::cout << "---Testing Color Mode " << ReadbackHelper::getColorModeString(mode) << "---"
@@ -327,15 +479,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -350,8 +496,7 @@
layer->write(mWriter);
// This following buffer call should have no effect
- uint64_t usage =
- static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN);
+ uint32_t usage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN;
NativeHandleWrapper bufferHandle =
mGralloc->allocate(mDisplayWidth, mDisplayHeight, 1, PixelFormat::RGBA_8888, usage);
mWriter->setLayerBuffer(0, bufferHandle.get(), -1);
@@ -360,8 +505,8 @@
std::vector<IComposerClient::Color> expectedColors(mDisplayWidth * mDisplayHeight);
ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, coloredSquare, BLUE);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mWriter->validateDisplay();
@@ -392,15 +537,11 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ PixelFormat pixelFormat;
+ Dataspace dataspace;
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &pixelFormat,
+ &dataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(pixelFormat, dataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -428,8 +569,8 @@
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
ASSERT_EQ(0, mReader->mErrors.size());
@@ -441,9 +582,8 @@
ASSERT_EQ(1, mReader->mCompositionChanges[0].second);
PixelFormat clientFormat = PixelFormat::RGBA_8888;
- uint64_t clientUsage = static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN |
- BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_CLIENT_TARGET);
+ uint32_t clientUsage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_HW_FB;
Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
IComposerClient::Rect damage{0, 0, mDisplayWidth, mDisplayHeight};
@@ -510,15 +650,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -531,8 +665,8 @@
ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
{0, mDisplayHeight / 2, mDisplayWidth, mDisplayHeight}, RED);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
auto deviceLayer = std::make_shared<TestBufferLayer>(
@@ -552,9 +686,8 @@
deviceLayer->write(mWriter);
PixelFormat clientFormat = PixelFormat::RGBA_8888;
- uint64_t clientUsage =
- static_cast<uint64_t>(BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_CLIENT_TARGET);
+ uint32_t clientUsage =
+ GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_HW_FB;
Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
int32_t clientWidth = mDisplayWidth;
int32_t clientHeight = mDisplayHeight / 2;
@@ -633,15 +766,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -665,8 +792,8 @@
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
@@ -718,15 +845,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -742,8 +863,8 @@
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
@@ -779,15 +900,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -819,8 +934,8 @@
// update expected colors to match crop
ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth,
{0, 0, mDisplayWidth, mDisplayHeight}, BLUE);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
ASSERT_EQ(0, mReader->mErrors.size());
@@ -850,15 +965,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -886,8 +995,8 @@
ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, blueRect, BLUE);
ReadbackHelper::fillColorsArea(expectedColors, mDisplayWidth, redRect, RED);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
@@ -1019,15 +1128,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -1043,8 +1146,8 @@
setUpLayers(IComposerClient::BlendMode::NONE);
setExpectedColors(expectedColors);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(mLayers);
ASSERT_EQ(0, mReader->mErrors.size());
@@ -1077,15 +1180,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -1102,8 +1199,8 @@
setUpLayers(IComposerClient::BlendMode::COVERAGE);
setExpectedColors(expectedColors);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(mLayers);
ASSERT_EQ(0, mReader->mErrors.size());
@@ -1130,15 +1227,9 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
@@ -1153,8 +1244,8 @@
setUpLayers(IComposerClient::BlendMode::PREMULTIPLIED);
setExpectedColors(expectedColors);
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(mLayers);
ASSERT_EQ(0, mReader->mErrors.size());
@@ -1222,22 +1313,16 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
return;
}
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mLayer->setTransform(Transform::FLIP_H);
mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), mWriter);
@@ -1277,22 +1362,16 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
return;
}
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mLayer->setTransform(Transform::FLIP_V);
@@ -1332,22 +1411,16 @@
ASSERT_NO_FATAL_FAILURE(
mComposerClient->setColorMode(mPrimaryDisplay, mode, RenderIntent::COLORIMETRIC));
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = ReadbackHelper::readbackSupported(tmpPixelFormat,
- tmpDataspace, tmpError);
- mPixelFormat = tmpPixelFormat;
- mDataspace = tmpDataspace;
- });
-
+ Error error = mComposerClient->getReadbackBufferAttributes(mPrimaryDisplay, &mPixelFormat,
+ &mDataspace);
+ mHasReadbackBuffer = ReadbackHelper::readbackSupported(mPixelFormat, mDataspace, error);
if (!mHasReadbackBuffer) {
std::cout << "Readback not supported or unsupported pixelFormat/dataspace" << std::endl;
GTEST_SUCCEED() << "Readback not supported or unsupported pixelFormat/dataspace";
return;
}
- ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mGralloc, mDisplayWidth,
- mDisplayHeight, mPixelFormat, mDataspace);
+ ReadbackBuffer readbackBuffer(mPrimaryDisplay, mComposerClient, mDisplayWidth,
+ mDisplayHeight, mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mLayer->setTransform(Transform::ROT_180);
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
index 7e25a2e..f8fbb04 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2TargetTest.cpp
@@ -23,6 +23,7 @@
#include <composer-vts/2.1/TestCommandReader.h>
#include <composer-vts/2.2/ComposerVts.h>
#include <gtest/gtest.h>
+#include <hardware/gralloc.h>
#include <hidl/GtestPrinter.h>
#include <hidl/ServiceManagement.h>
#include <mapper-vts/2.0/MapperVts.h>
@@ -35,7 +36,6 @@
namespace vts {
namespace {
-using common::V1_0::BufferUsage;
using common::V1_1::ColorMode;
using common::V1_1::Dataspace;
using common::V1_1::PixelFormat;
@@ -65,17 +65,13 @@
mComposerClient->setVsyncEnabled(mPrimaryDisplay, false);
mComposerCallback->setVsyncAllowed(false);
- mComposerClient->getRaw()->getReadbackBufferAttributes(
- mPrimaryDisplay,
- [&](const auto& tmpError, const auto& tmpPixelFormat, const auto& tmpDataspace) {
- mHasReadbackBuffer = tmpError == Error::NONE;
- if (mHasReadbackBuffer) {
- mReadbackPixelFormat = tmpPixelFormat;
- mReadbackDataspace = tmpDataspace;
- ASSERT_LT(static_cast<PixelFormat>(0), mReadbackPixelFormat);
- ASSERT_NE(Dataspace::UNKNOWN, mReadbackDataspace);
- }
- });
+ Error error = mComposerClient->getReadbackBufferAttributes(
+ mPrimaryDisplay, &mReadbackPixelFormat, &mReadbackDataspace);
+ mHasReadbackBuffer = error == Error::NONE;
+ if (mHasReadbackBuffer) {
+ ASSERT_LT(static_cast<PixelFormat>(0), mReadbackPixelFormat);
+ ASSERT_NE(Dataspace::UNKNOWN, mReadbackDataspace);
+ }
mInvalidDisplayId = GetInvalidDisplayId();
}
@@ -153,10 +149,9 @@
}
NativeHandleWrapper allocate() {
- uint64_t usage =
- static_cast<uint64_t>(BufferUsage::CPU_WRITE_OFTEN | BufferUsage::CPU_READ_OFTEN);
return mGralloc->allocate(/*width*/ 64, /*height*/ 64, /*layerCount*/ 1,
- PixelFormat::RGBA_8888, usage);
+ PixelFormat::RGBA_8888,
+ GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN);
}
void execute() { mComposerClient->execute(mReader.get(), mWriter.get()); }
@@ -434,9 +429,7 @@
}
// BufferUsage::COMPOSER_OUTPUT is missing
- uint64_t usage =
- static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN);
-
+ uint64_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_SW_READ_OFTEN;
std::unique_ptr<Gralloc> gralloc;
std::unique_ptr<NativeHandleWrapper> buffer;
ASSERT_NO_FATAL_FAILURE(gralloc = std::make_unique<Gralloc>());
@@ -457,9 +450,7 @@
return;
}
- uint64_t usage =
- static_cast<uint64_t>(BufferUsage::COMPOSER_OVERLAY | BufferUsage::CPU_READ_OFTEN);
-
+ uint64_t usage = GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_SW_READ_OFTEN;
std::unique_ptr<Gralloc> gralloc;
std::unique_ptr<NativeHandleWrapper> buffer;
ASSERT_NO_FATAL_FAILURE(gralloc = std::make_unique<Gralloc>());
diff --git a/graphics/composer/aidl/vts/ReadbackVts.cpp b/graphics/composer/aidl/vts/ReadbackVts.cpp
index abb58e2..b59793f 100644
--- a/graphics/composer/aidl/vts/ReadbackVts.cpp
+++ b/graphics/composer/aidl/vts/ReadbackVts.cpp
@@ -20,6 +20,8 @@
#include "renderengine/ExternalTexture.h"
#include "renderengine/impl/ExternalTexture.h"
+using ::android::status_t;
+
namespace aidl::android::hardware::graphics::composer3::vts {
const std::vector<ColorMode> ReadbackHelper::colorModes = {ColorMode::SRGB, ColorMode::DISPLAY_P3};
@@ -27,6 +29,9 @@
common::Dataspace::DISPLAY_P3};
void TestLayer::write(ComposerClientWriter& writer) {
+ ::android::status_t status = ::android::OK;
+ ASSERT_EQ(::android::OK, status);
+
writer.setLayerDisplayFrame(mDisplay, mLayer, mDisplayFrame);
writer.setLayerSourceCrop(mDisplay, mLayer, mSourceCrop);
writer.setLayerZOrder(mDisplay, mLayer, mZOrder);
@@ -37,6 +42,40 @@
writer.setLayerBrightness(mDisplay, mLayer, mBrightness);
}
+bool ReadbackHelper::readbackSupported(const common::PixelFormat& pixelFormat,
+ const common::Dataspace& dataspace) {
+ // TODO: add support for RGBA_1010102
+ if (pixelFormat != common::PixelFormat::RGB_888 &&
+ pixelFormat != common::PixelFormat::RGBA_8888) {
+ return false;
+ }
+ if (std::find(dataspaces.begin(), dataspaces.end(), dataspace) == dataspaces.end()) {
+ return false;
+ }
+ return true;
+}
+
+void ReadbackHelper::createReadbackBuffer(ReadbackBufferAttributes readbackBufferAttributes,
+ const VtsDisplay& display,
+ sp<GraphicBuffer>* graphicBuffer) {
+ ASSERT_NE(nullptr, graphicBuffer);
+ if (!readbackSupported(readbackBufferAttributes.format, readbackBufferAttributes.dataspace)) {
+ *graphicBuffer = nullptr;
+ }
+ uint64_t usage =
+ static_cast<uint64_t>(static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
+ static_cast<uint64_t>(common::BufferUsage::GPU_TEXTURE));
+
+ uint32_t layerCount = 1;
+ *graphicBuffer = sp<GraphicBuffer>::make(
+ static_cast<uint32_t>(display.getDisplayWidth()),
+ static_cast<uint32_t>(display.getDisplayHeight()),
+ static_cast<::android::PixelFormat>(readbackBufferAttributes.format), layerCount, usage,
+ "ReadbackBuffer");
+ ASSERT_NE(nullptr, *graphicBuffer);
+ ASSERT_EQ(::android::OK, (*graphicBuffer)->initCheck());
+}
+
std::string ReadbackHelper::getColorModeString(ColorMode mode) {
switch (mode) {
case ColorMode::SRGB:
@@ -103,11 +142,11 @@
return layerSettings;
}
-int32_t ReadbackHelper::GetBytesPerPixel(common::PixelFormat pixelFormat) {
+int32_t ReadbackHelper::GetBytesPerPixel(PixelFormat pixelFormat) {
switch (pixelFormat) {
- case common::PixelFormat::RGBA_8888:
+ case PixelFormat::RGBA_8888:
return 4;
- case common::PixelFormat::RGB_888:
+ case PixelFormat::RGB_888:
return 3;
default:
return -1;
@@ -116,136 +155,161 @@
void ReadbackHelper::fillBuffer(uint32_t width, uint32_t height, uint32_t stride, void* bufferData,
common::PixelFormat pixelFormat,
- std::vector<Color> desiredPixelColors) {
+ const std::vector<Color>& desiredColors) {
ASSERT_TRUE(pixelFormat == common::PixelFormat::RGB_888 ||
pixelFormat == common::PixelFormat::RGBA_8888);
int32_t bytesPerPixel = GetBytesPerPixel(pixelFormat);
ASSERT_NE(-1, bytesPerPixel);
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
- auto pixel = row * static_cast<int32_t>(width) + col;
- Color srcColor = desiredPixelColors[static_cast<size_t>(pixel)];
+ int pixel = row * static_cast<int32_t>(width) + col;
+ Color desiredColor = desiredColors[static_cast<size_t>(pixel)];
int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
uint8_t* pixelColor = (uint8_t*)bufferData + offset;
- pixelColor[0] = static_cast<uint8_t>(std::round(255.0f * srcColor.r));
- pixelColor[1] = static_cast<uint8_t>(std::round(255.0f * srcColor.g));
- pixelColor[2] = static_cast<uint8_t>(std::round(255.0f * srcColor.b));
+ pixelColor[0] = static_cast<uint8_t>(std::round(255.0f * desiredColor.r));
+ pixelColor[1] = static_cast<uint8_t>(std::round(255.0f * desiredColor.g));
+ pixelColor[2] = static_cast<uint8_t>(std::round(255.0f * desiredColor.b));
if (bytesPerPixel == 4) {
- pixelColor[3] = static_cast<uint8_t>(std::round(255.0f * srcColor.a));
+ pixelColor[3] = static_cast<uint8_t>(std::round(255.0f * desiredColor.a));
}
}
}
}
-void ReadbackHelper::clearColors(std::vector<Color>& expectedColors, int32_t width, int32_t height,
+void ReadbackHelper::clearColors(std::vector<Color>& colors, int32_t width, int32_t height,
int32_t displayWidth) {
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
int pixel = row * displayWidth + col;
- expectedColors[static_cast<size_t>(pixel)] = BLACK;
+ colors[static_cast<size_t>(pixel)] = BLACK;
}
}
}
-void ReadbackHelper::fillColorsArea(std::vector<Color>& expectedColors, int32_t stride, Rect area,
- Color color) {
+void ReadbackHelper::fillColorsArea(std::vector<Color>& colors, int32_t stride, Rect area,
+ Color desiredColor) {
for (int row = area.top; row < area.bottom; row++) {
for (int col = area.left; col < area.right; col++) {
int pixel = row * stride + col;
- expectedColors[static_cast<size_t>(pixel)] = color;
+ colors[static_cast<size_t>(pixel)] = desiredColor;
}
}
}
-bool ReadbackHelper::readbackSupported(const common::PixelFormat& pixelFormat,
- const common::Dataspace& dataspace) {
- if (pixelFormat != common::PixelFormat::RGB_888 &&
- pixelFormat != common::PixelFormat::RGBA_8888) {
- return false;
- }
- if (std::find(dataspaces.begin(), dataspaces.end(), dataspace) == dataspaces.end()) {
- return false;
- }
- return true;
+void ReadbackHelper::fillBufferAndGetFence(const sp<GraphicBuffer>& graphicBuffer,
+ Color desiredColor, int* fillFence) {
+ ASSERT_NE(nullptr, fillFence);
+ std::vector<Color> desiredColors(
+ static_cast<size_t>(graphicBuffer->getWidth() * graphicBuffer->getHeight()));
+ ::android::Rect bounds = graphicBuffer->getBounds();
+ fillColorsArea(desiredColors, static_cast<int32_t>(graphicBuffer->getWidth()),
+ {bounds.left, bounds.top, bounds.right, bounds.bottom}, desiredColor);
+ ASSERT_NO_FATAL_FAILURE(fillBufferAndGetFence(graphicBuffer, desiredColors, fillFence));
}
-void ReadbackHelper::compareColorBuffers(const std::vector<Color>& expectedColors, void* bufferData,
- const uint32_t stride, const uint32_t width,
- const uint32_t height, common::PixelFormat pixelFormat) {
- const int32_t bytesPerPixel = ReadbackHelper::GetBytesPerPixel(pixelFormat);
+void ReadbackHelper::fillBufferAndGetFence(const sp<GraphicBuffer>& graphicBuffer,
+ const std::vector<Color>& desiredColors,
+ int* fillFence) {
+ ASSERT_TRUE(graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGB_888 ||
+ graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGBA_8888);
+ void* bufData;
+ int32_t bytesPerPixel = -1;
+ int32_t bytesPerStride = -1;
+ status_t status =
+ graphicBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ &bufData, &bytesPerPixel, &bytesPerStride);
+ ASSERT_EQ(::android::OK, status);
+
+ const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
+ ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
+ : graphicBuffer->getStride();
+ ReadbackHelper::fillBuffer(
+ graphicBuffer->getWidth(), graphicBuffer->getHeight(), stride, bufData,
+ static_cast<common::PixelFormat>(graphicBuffer->getPixelFormat()), desiredColors);
+ status = graphicBuffer->unlockAsync(fillFence);
+ ASSERT_EQ(::android::OK, status);
+}
+
+void ReadbackHelper::compareColorToBuffer(Color expectedColor,
+ const sp<GraphicBuffer>& graphicBuffer,
+ const ndk::ScopedFileDescriptor& fence) {
+ std::vector<Color> expectedColors(
+ static_cast<size_t>(graphicBuffer->getWidth() * graphicBuffer->getHeight()));
+ ::android::Rect bounds = graphicBuffer->getBounds();
+ fillColorsArea(expectedColors, static_cast<int32_t>(graphicBuffer->getWidth()),
+ {bounds.left, bounds.top, bounds.right, bounds.bottom}, expectedColor);
+ compareColorsToBuffer(expectedColors, graphicBuffer, fence);
+}
+
+void ReadbackHelper::compareColorsToBuffer(const std::vector<Color>& expectedColors,
+ const sp<GraphicBuffer>& graphicBuffer,
+ const ndk::ScopedFileDescriptor& fence) {
+ ASSERT_TRUE(graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGB_888 ||
+ graphicBuffer->getPixelFormat() == ::android::PIXEL_FORMAT_RGBA_8888);
+
+ int bytesPerPixel = -1;
+ int bytesPerStride = -1;
+ void* bufData = nullptr;
+ status_t status = graphicBuffer->lockAsync(GRALLOC_USAGE_SW_READ_OFTEN, &bufData,
+ dup(fence.get()), &bytesPerPixel, &bytesPerStride);
+ ASSERT_EQ(::android::OK, status);
+
+ const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
+ ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
+ : graphicBuffer->getStride();
+
+ if (bytesPerPixel == -1) {
+ bytesPerPixel = ReadbackHelper::GetBytesPerPixel(
+ static_cast<PixelFormat>(graphicBuffer->getPixelFormat()));
+ }
ASSERT_NE(-1, bytesPerPixel);
- for (int row = 0; row < height; row++) {
- for (int col = 0; col < width; col++) {
- auto pixel = row * static_cast<int32_t>(width) + col;
+ for (int row = 0; row < graphicBuffer->getHeight(); row++) {
+ for (int col = 0; col < graphicBuffer->getWidth(); col++) {
+ int pixel = row * static_cast<int32_t>(graphicBuffer->getWidth()) + col;
int offset = (row * static_cast<int32_t>(stride) + col) * bytesPerPixel;
- uint8_t* pixelColor = (uint8_t*)bufferData + offset;
+ uint8_t* pixelColor = (uint8_t*)bufData + offset;
const Color expectedColor = expectedColors[static_cast<size_t>(pixel)];
ASSERT_EQ(std::round(255.0f * expectedColor.r), pixelColor[0]);
ASSERT_EQ(std::round(255.0f * expectedColor.g), pixelColor[1]);
ASSERT_EQ(std::round(255.0f * expectedColor.b), pixelColor[2]);
}
}
+
+ status = graphicBuffer->unlock();
+ ASSERT_EQ(::android::OK, status);
}
ReadbackBuffer::ReadbackBuffer(int64_t display, const std::shared_ptr<VtsComposerClient>& client,
- int32_t width, int32_t height, common::PixelFormat pixelFormat,
- common::Dataspace dataspace)
+ int32_t width, int32_t height, common::PixelFormat pixelFormat)
: mComposerClient(client) {
mDisplay = display;
-
- mPixelFormat = pixelFormat;
- mDataspace = dataspace;
-
mWidth = static_cast<uint32_t>(width);
mHeight = static_cast<uint32_t>(height);
+ mPixelFormat = pixelFormat;
mLayerCount = 1;
mUsage = static_cast<uint64_t>(static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
static_cast<uint64_t>(common::BufferUsage::GPU_TEXTURE));
-
- mAccessRegion.top = 0;
- mAccessRegion.left = 0;
- mAccessRegion.right = static_cast<int32_t>(width);
- mAccessRegion.bottom = static_cast<int32_t>(height);
-}
-
-::android::sp<::android::GraphicBuffer> ReadbackBuffer::allocateBuffer() {
- return ::android::sp<::android::GraphicBuffer>::make(
- mWidth, mHeight, static_cast<::android::PixelFormat>(mPixelFormat), mLayerCount, mUsage,
- "ReadbackBuffer");
}
void ReadbackBuffer::setReadbackBuffer() {
- mGraphicBuffer = allocateBuffer();
+ mGraphicBuffer = sp<GraphicBuffer>::make(mWidth, mHeight,
+ static_cast<::android::PixelFormat>(mPixelFormat),
+ mLayerCount, mUsage, "ReadbackBuffer");
ASSERT_NE(nullptr, mGraphicBuffer);
ASSERT_EQ(::android::OK, mGraphicBuffer->initCheck());
- const auto& bufferHandle = mGraphicBuffer->handle;
- ::ndk::ScopedFileDescriptor fence = ::ndk::ScopedFileDescriptor(-1);
- EXPECT_TRUE(mComposerClient->setReadbackBuffer(mDisplay, bufferHandle, fence).isOk());
+ ::ndk::ScopedFileDescriptor noFence = ::ndk::ScopedFileDescriptor(-1);
+ const auto& status =
+ mComposerClient->setReadbackBuffer(mDisplay, mGraphicBuffer->handle, noFence);
+ ASSERT_TRUE(status.isOk());
}
void ReadbackBuffer::checkReadbackBuffer(const std::vector<Color>& expectedColors) {
- ASSERT_NE(nullptr, mGraphicBuffer);
// lock buffer for reading
const auto& [fenceStatus, bufferFence] = mComposerClient->getReadbackBufferFence(mDisplay);
- EXPECT_TRUE(fenceStatus.isOk());
-
- int bytesPerPixel = -1;
- int bytesPerStride = -1;
- void* bufData = nullptr;
-
- auto status = mGraphicBuffer->lockAsync(mUsage, mAccessRegion, &bufData, dup(bufferFence.get()),
- &bytesPerPixel, &bytesPerStride);
- EXPECT_EQ(::android::OK, status);
- ASSERT_TRUE(mPixelFormat == PixelFormat::RGB_888 || mPixelFormat == PixelFormat::RGBA_8888);
- const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
- ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
- : mGraphicBuffer->getStride();
- ReadbackHelper::compareColorBuffers(expectedColors, bufData, stride, mWidth, mHeight,
- mPixelFormat);
- status = mGraphicBuffer->unlock();
- EXPECT_EQ(::android::OK, status);
+ ASSERT_TRUE(fenceStatus.isOk());
+ ReadbackHelper::compareColorsToBuffer(expectedColors, mGraphicBuffer, bufferFence);
}
void TestColorLayer::write(ComposerClientWriter& writer) {
@@ -323,9 +387,8 @@
const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
: mGraphicBuffer->getStride();
- EXPECT_EQ(::android::OK, status);
- ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBuffer(mWidth, mHeight, stride, bufData,
- mPixelFormat, expectedColors));
+ ASSERT_EQ(::android::OK, status);
+ ReadbackHelper::fillBuffer(mWidth, mHeight, stride, bufData, mPixelFormat, expectedColors);
const auto unlockStatus = mGraphicBuffer->unlockAsync(&mFillFence);
ASSERT_EQ(::android::OK, unlockStatus);
@@ -335,13 +398,13 @@
mGraphicBuffer = allocateBuffer();
ASSERT_NE(nullptr, mGraphicBuffer);
ASSERT_EQ(::android::OK, mGraphicBuffer->initCheck());
- ASSERT_NO_FATAL_FAILURE(fillBuffer(colors));
+ fillBuffer(colors);
}
-::android::sp<::android::GraphicBuffer> TestBufferLayer::allocateBuffer() {
- return ::android::sp<::android::GraphicBuffer>::make(
- mWidth, mHeight, static_cast<::android::PixelFormat>(mPixelFormat), mLayerCount, mUsage,
- "TestBufferLayer");
+sp<GraphicBuffer> TestBufferLayer::allocateBuffer() {
+ return sp<GraphicBuffer>::make(mWidth, mHeight,
+ static_cast<::android::PixelFormat>(mPixelFormat), mLayerCount,
+ mUsage, "TestBufferLayer");
}
void TestBufferLayer::setDataspace(common::Dataspace dataspace, ComposerClientWriter& writer) {
diff --git a/graphics/composer/aidl/vts/ReadbackVts.h b/graphics/composer/aidl/vts/ReadbackVts.h
index ee9f0d5..ecf0d52 100644
--- a/graphics/composer/aidl/vts/ReadbackVts.h
+++ b/graphics/composer/aidl/vts/ReadbackVts.h
@@ -33,6 +33,8 @@
using common::Dataspace;
using common::PixelFormat;
using IMapper2_1 = ::android::hardware::graphics::mapper::V2_1::IMapper;
+using ::android::GraphicBuffer;
+using ::android::sp;
static const Color BLACK = {0.0f, 0.0f, 0.0f, 1.0f};
static const Color RED = {1.0f, 0.0f, 0.0f, 1.0f};
@@ -146,7 +148,7 @@
protected:
Composition mComposition;
- ::android::sp<::android::GraphicBuffer> mGraphicBuffer;
+ sp<GraphicBuffer> mGraphicBuffer;
TestRenderEngine& mRenderEngine;
int32_t mFillFence;
uint32_t mWidth;
@@ -162,6 +164,11 @@
class ReadbackHelper {
public:
+ static bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace);
+
+ static void createReadbackBuffer(ReadbackBufferAttributes readbackBufferAttributes,
+ const VtsDisplay& display, sp<GraphicBuffer>* graphicBuffer);
+
static std::string getColorModeString(ColorMode mode);
static std::string getDataspaceString(Dataspace dataspace);
@@ -171,28 +178,36 @@
static int32_t GetBytesPerPixel(PixelFormat pixelFormat);
static void fillBuffer(uint32_t width, uint32_t height, uint32_t stride, void* bufferData,
- PixelFormat pixelFormat, std::vector<Color> desiredPixelColors);
+ PixelFormat pixelFormat, const std::vector<Color>& desriedColors);
- static void clearColors(std::vector<Color>& expectedColors, int32_t width, int32_t height,
+ static void clearColors(std::vector<Color>& colors, int32_t width, int32_t height,
int32_t displayWidth);
- static void fillColorsArea(std::vector<Color>& expectedColors, int32_t stride, Rect area,
- Color color);
+ static void fillColorsArea(std::vector<Color>& colors, int32_t stride, Rect area,
+ Color desiredColor);
- static bool readbackSupported(const PixelFormat& pixelFormat, const Dataspace& dataspace);
+ static void fillBufferAndGetFence(const sp<GraphicBuffer>& buffer, Color desiredColor,
+ int* fillFence);
+
+ static void fillBufferAndGetFence(const sp<GraphicBuffer>& buffer,
+ const std::vector<Color>& desiredColors, int* fillFence);
+
+ static void compareColorToBuffer(
+ Color expectedColor, const sp<GraphicBuffer>& graphicBuffer,
+ const ndk::ScopedFileDescriptor& fence = ::ndk::ScopedFileDescriptor(-1));
+
+ static void compareColorsToBuffer(
+ const std::vector<Color>& expectedColors, const sp<GraphicBuffer>& graphicBuffer,
+ const ndk::ScopedFileDescriptor& fence = ::ndk::ScopedFileDescriptor(-1));
static const std::vector<ColorMode> colorModes;
static const std::vector<Dataspace> dataspaces;
-
- static void compareColorBuffers(const std::vector<Color>& expectedColors, void* bufferData,
- const uint32_t stride, const uint32_t width,
- const uint32_t height, PixelFormat pixelFormat);
};
class ReadbackBuffer {
public:
ReadbackBuffer(int64_t display, const std::shared_ptr<VtsComposerClient>& client, int32_t width,
- int32_t height, common::PixelFormat pixelFormat, common::Dataspace dataspace);
+ int32_t height, common::PixelFormat pixelFormat);
void setReadbackBuffer();
@@ -201,18 +216,12 @@
protected:
uint32_t mWidth;
uint32_t mHeight;
+ PixelFormat mPixelFormat;
uint32_t mLayerCount;
uint32_t mUsage;
- PixelFormat mPixelFormat;
- Dataspace mDataspace;
int64_t mDisplay;
- ::android::sp<::android::GraphicBuffer> mGraphicBuffer;
+ sp<GraphicBuffer> mGraphicBuffer;
std::shared_ptr<VtsComposerClient> mComposerClient;
- ::android::Rect mAccessRegion;
- native_handle_t mBufferHandle;
-
- private:
- ::android::sp<::android::GraphicBuffer> allocateBuffer();
};
} // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/vts/RenderEngineVts.cpp b/graphics/composer/aidl/vts/RenderEngineVts.cpp
index 66779c8..b84d0d0 100644
--- a/graphics/composer/aidl/vts/RenderEngineVts.cpp
+++ b/graphics/composer/aidl/vts/RenderEngineVts.cpp
@@ -76,18 +76,7 @@
}
void TestRenderEngine::checkColorBuffer(const std::vector<Color>& expectedColors) {
- void* bufferData;
- int32_t bytesPerPixel = -1;
- int32_t bytesPerStride = -1;
- ASSERT_EQ(0, mGraphicBuffer->lock(static_cast<uint32_t>(mGraphicBuffer->getUsage()),
- &bufferData, &bytesPerPixel, &bytesPerStride));
- const uint32_t stride = (bytesPerPixel > 0 && bytesPerStride > 0)
- ? static_cast<uint32_t>(bytesPerStride / bytesPerPixel)
- : mGraphicBuffer->getStride();
- ReadbackHelper::compareColorBuffers(expectedColors, bufferData, stride,
- mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight(),
- mFormat);
- ASSERT_EQ(::android::OK, mGraphicBuffer->unlock());
+ ReadbackHelper::compareColorsToBuffer(expectedColors, mGraphicBuffer);
}
} // namespace aidl::android::hardware::graphics::composer3::vts
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
index 6fa3392..93d9693 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_ReadbackTest.cpp
@@ -18,7 +18,6 @@
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
-#include <aidl/android/hardware/graphics/common/BufferUsage.h>
#include <aidl/android/hardware/graphics/composer3/IComposer.h>
#include <gtest/gtest.h>
#include <ui/DisplayId.h>
@@ -81,13 +80,11 @@
clientCompositionDisplay.physicalDisplay = Rect(getDisplayWidth(), getDisplayHeight());
clientCompositionDisplay.clip = clientCompositionDisplay.physicalDisplay;
- mTestRenderEngine->initGraphicBuffer(
- static_cast<uint32_t>(getDisplayWidth()), static_cast<uint32_t>(getDisplayHeight()),
- /*layerCount*/ 1U,
- static_cast<uint64_t>(
- static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
- static_cast<uint64_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
- static_cast<uint64_t>(common::BufferUsage::GPU_RENDER_TARGET)));
+ mTestRenderEngine->initGraphicBuffer(static_cast<uint32_t>(getDisplayWidth()),
+ static_cast<uint32_t>(getDisplayHeight()),
+ /*layerCount*/ 1U,
+ GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN);
mTestRenderEngine->setDisplaySettings(clientCompositionDisplay);
}
@@ -115,18 +112,21 @@
ASSERT_EQ(status.getServiceSpecificError(), serviceSpecificError);
}
- std::pair<bool, ::android::sp<::android::GraphicBuffer>> allocateBuffer(uint32_t usage) {
- const auto width = static_cast<uint32_t>(getDisplayWidth());
- const auto height = static_cast<uint32_t>(getDisplayHeight());
-
- const auto& graphicBuffer = ::android::sp<::android::GraphicBuffer>::make(
- width, height, ::android::PIXEL_FORMAT_RGBA_8888,
- /*layerCount*/ 1u, usage, "VtsHalGraphicsComposer3_ReadbackTest");
+ sp<GraphicBuffer> allocateBuffer(uint32_t width, uint32_t height, uint64_t usage) {
+ sp<GraphicBuffer> graphicBuffer =
+ sp<GraphicBuffer>::make(width, height, ::android::PIXEL_FORMAT_RGBA_8888,
+ /*layerCount*/ 1u, static_cast<uint32_t>(usage),
+ "VtsHalGraphicsComposer3_ReadbackTest");
if (graphicBuffer && ::android::OK == graphicBuffer->initCheck()) {
- return {true, graphicBuffer};
+ return graphicBuffer;
}
- return {false, graphicBuffer};
+ return nullptr;
+ }
+
+ sp<GraphicBuffer> allocateBuffer(uint64_t usage) {
+ return allocateBuffer(static_cast<uint32_t>(getDisplayWidth()),
+ static_cast<uint32_t>(getDisplayHeight()), usage);
}
uint64_t getStableDisplayId(int64_t display) {
@@ -293,7 +293,7 @@
ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), coloredSquare, BLUE);
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
@@ -332,7 +332,7 @@
}
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
std::vector<Color> expectedColors(
static_cast<size_t>(getDisplayWidth() * getDisplayHeight()));
@@ -378,6 +378,143 @@
}
}
+TEST_P(GraphicsCompositionTest, SetLayerBufferWithSlotsToClear) {
+ const auto& [status, readbackBufferAttributes] =
+ mComposerClient->getReadbackBufferAttributes(getPrimaryDisplayId());
+ if (!status.isOk()) {
+ GTEST_SUCCEED() << "Readback not supported";
+ return;
+ }
+
+ sp<GraphicBuffer> readbackBuffer;
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::createReadbackBuffer(
+ readbackBufferAttributes, getPrimaryDisplay(), &readbackBuffer));
+ if (readbackBuffer == nullptr) {
+ GTEST_SUCCEED() << "Unsupported readback buffer attributes";
+ return;
+ }
+ // no fence needed for the readback buffer
+ ScopedFileDescriptor noFence(-1);
+
+ sp<GraphicBuffer> clearSlotBuffer = allocateBuffer(1u, 1u, GRALLOC_USAGE_HW_COMPOSER);
+ ASSERT_NE(nullptr, clearSlotBuffer);
+
+ // red buffer
+ uint64_t usage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN;
+ sp<GraphicBuffer> redBuffer = allocateBuffer(usage);
+ ASSERT_NE(nullptr, redBuffer);
+ int redFence;
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(redBuffer, RED, &redFence));
+
+ // blue buffer
+ sp<GraphicBuffer> blueBuffer = allocateBuffer(usage);
+ ASSERT_NE(nullptr, blueBuffer);
+ int blueFence;
+ ASSERT_NO_FATAL_FAILURE(ReadbackHelper::fillBufferAndGetFence(blueBuffer, BLUE, &blueFence));
+
+ // layer defaults
+ common::Rect rectFullDisplay = {0, 0, getDisplayWidth(), getDisplayHeight()};
+ int64_t display = getPrimaryDisplayId();
+ auto [layerStatus, layer] = mComposerClient->createLayer(getPrimaryDisplayId(), 3);
+ ASSERT_TRUE(layerStatus.isOk());
+ mWriter->setLayerDisplayFrame(display, layer, rectFullDisplay);
+ mWriter->setLayerCompositionType(display, layer, Composition::DEVICE);
+
+ // set the layer to the blue buffer
+ // should be blue
+ {
+ auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+ ASSERT_TRUE(status.isOk());
+ mWriter->setLayerBuffer(display, layer, /*slot*/ 0, blueBuffer->handle, blueFence);
+ mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+ execute();
+ ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+ ASSERT_TRUE(mReader.takeErrors().empty());
+ mWriter->presentDisplay(display);
+ execute();
+ auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+ ASSERT_TRUE(fenceStatus.isOk());
+ ReadbackHelper::compareColorToBuffer(BLUE, readbackBuffer, fence);
+ }
+
+ // change the layer to the red buffer
+ // should be red
+ {
+ auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+ ASSERT_TRUE(status.isOk());
+ mWriter->setLayerBuffer(display, layer, /*slot*/ 1, redBuffer->handle, redFence);
+ mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+ execute();
+ ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+ ASSERT_TRUE(mReader.takeErrors().empty());
+ mWriter->presentDisplay(display);
+ execute();
+ auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+ ASSERT_TRUE(fenceStatus.isOk());
+ ReadbackHelper::compareColorToBuffer(RED, readbackBuffer, fence);
+ }
+
+ // clear the slot for the blue buffer
+ // should still be red
+ {
+ auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+ ASSERT_TRUE(status.isOk());
+ mWriter->setLayerBufferWithNewCommand(display, layer, /*slot*/ 0, clearSlotBuffer->handle,
+ /*fence*/ -1);
+ mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+ execute();
+ ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+ ASSERT_TRUE(mReader.takeErrors().empty());
+ mWriter->presentDisplay(display);
+ execute();
+ auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+ ASSERT_TRUE(fenceStatus.isOk());
+ ReadbackHelper::compareColorToBuffer(RED, readbackBuffer, fence);
+ }
+
+ // clear the slot for the red buffer, and set the buffer with the same slot to the blue buffer
+ // should be blue
+ {
+ auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+ ASSERT_TRUE(status.isOk());
+ mWriter->setLayerBufferWithNewCommand(display, layer, /*slot*/ 1, clearSlotBuffer->handle,
+ /*fence*/ -1);
+ mWriter->setLayerBuffer(display, layer, /*slot*/ 1, blueBuffer->handle, blueFence);
+ mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+ execute();
+ ASSERT_TRUE(mReader.takeChangedCompositionTypes(display).empty());
+ ASSERT_TRUE(mReader.takeErrors().empty());
+ mWriter->presentDisplay(display);
+ execute();
+ auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+ ASSERT_TRUE(fenceStatus.isOk());
+ ReadbackHelper::compareColorToBuffer(BLUE, readbackBuffer, fence);
+ }
+
+ // clear the slot for the now-blue buffer
+ // should be black (no buffer)
+ // TODO(b/262037933) Ensure we never clear the active buffer's slot with the placeholder buffer
+ // by setting the layer to the color black
+ {
+ auto status = mComposerClient->setReadbackBuffer(display, readbackBuffer->handle, noFence);
+ ASSERT_TRUE(status.isOk());
+ mWriter->setLayerBufferWithNewCommand(display, layer, /*slot*/ 1, clearSlotBuffer->handle,
+ /*fence*/ -1);
+ mWriter->validateDisplay(display, ComposerClientWriter::kNoTimestamp);
+ execute();
+ if (!mReader.takeChangedCompositionTypes(display).empty()) {
+ GTEST_SUCCEED();
+ return;
+ }
+ ASSERT_TRUE(mReader.takeErrors().empty());
+ mWriter->presentDisplay(display);
+ execute();
+ auto [fenceStatus, fence] = mComposerClient->getReadbackBufferFence(display);
+ ASSERT_TRUE(fenceStatus.isOk());
+ ReadbackHelper::compareColorToBuffer(BLACK, readbackBuffer, fence);
+ }
+}
+
TEST_P(GraphicsCompositionTest, SetLayerBufferNoEffect) {
for (ColorMode mode : mTestColorModes) {
EXPECT_TRUE(mComposerClient
@@ -399,10 +536,9 @@
layer->write(*mWriter);
// This following buffer call should have no effect
- const auto usage = static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
- static_cast<uint32_t>(common::BufferUsage::CPU_READ_OFTEN);
- const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(usage);
- ASSERT_TRUE(graphicBufferStatus);
+ uint64_t usage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN;
+ sp<GraphicBuffer> graphicBuffer = allocateBuffer(usage);
+ ASSERT_NE(nullptr, graphicBuffer);
const auto& buffer = graphicBuffer->handle;
mWriter->setLayerBuffer(getPrimaryDisplayId(), layer->getLayer(), /*slot*/ 0, buffer,
/*acquireFence*/ -1);
@@ -413,7 +549,7 @@
ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), coloredSquare, BLUE);
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mWriter->validateDisplay(getPrimaryDisplayId(), ComposerClientWriter::kNoTimestamp);
@@ -441,7 +577,7 @@
}
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
}
@@ -454,10 +590,9 @@
return;
}
- const auto usage = static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
- static_cast<uint32_t>(common::BufferUsage::CPU_READ_OFTEN);
- const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(usage);
- ASSERT_TRUE(graphicBufferStatus);
+ uint64_t usage = GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN;
+ sp<GraphicBuffer> graphicBuffer = allocateBuffer(usage);
+ ASSERT_NE(nullptr, graphicBuffer);
const auto& bufferHandle = graphicBuffer->handle;
::ndk::ScopedFileDescriptor fence = ::ndk::ScopedFileDescriptor(-1);
@@ -539,7 +674,7 @@
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -552,16 +687,14 @@
ASSERT_EQ(Composition::CLIENT, changedCompositionTypes[0].composition);
PixelFormat clientFormat = PixelFormat::RGBA_8888;
- auto clientUsage = static_cast<uint32_t>(
- static_cast<uint32_t>(common::BufferUsage::CPU_READ_OFTEN) |
- static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
- static_cast<uint32_t>(common::BufferUsage::COMPOSER_CLIENT_TARGET));
+ auto clientUsage = GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_OFTEN;
Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
common::Rect damage{0, 0, getDisplayWidth(), getDisplayHeight()};
// create client target buffer
- const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(clientUsage);
- ASSERT_TRUE(graphicBufferStatus);
+ sp<GraphicBuffer> graphicBuffer = allocateBuffer(clientUsage);
+ ASSERT_NE(nullptr, graphicBuffer);
const auto& buffer = graphicBuffer->handle;
void* clientBufData;
const auto stride = static_cast<uint32_t>(graphicBuffer->stride);
@@ -618,7 +751,7 @@
{0, getDisplayHeight() / 2, getDisplayWidth(), getDisplayHeight()}, RED);
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
auto deviceLayer = std::make_shared<TestBufferLayer>(
@@ -637,10 +770,8 @@
deviceLayer->write(*mWriter);
PixelFormat clientFormat = PixelFormat::RGBA_8888;
- auto clientUsage = static_cast<uint32_t>(
- static_cast<uint64_t>(common::BufferUsage::CPU_READ_OFTEN) |
- static_cast<uint32_t>(common::BufferUsage::CPU_WRITE_OFTEN) |
- static_cast<uint32_t>(common::BufferUsage::COMPOSER_CLIENT_TARGET));
+ auto clientUsage =
+ GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
Dataspace clientDataspace = ReadbackHelper::getDataspaceForColorMode(mode);
int32_t clientWidth = getDisplayWidth();
int32_t clientHeight = getDisplayHeight() / 2;
@@ -662,8 +793,8 @@
}
// create client target buffer
ASSERT_EQ(Composition::CLIENT, changedCompositionTypes[0].composition);
- const auto& [graphicBufferStatus, graphicBuffer] = allocateBuffer(clientUsage);
- ASSERT_TRUE(graphicBufferStatus);
+ sp<GraphicBuffer> graphicBuffer = allocateBuffer(clientUsage);
+ ASSERT_NE(nullptr, graphicBuffer);
const auto& buffer = graphicBuffer->handle;
void* clientBufData;
@@ -725,7 +856,7 @@
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
@@ -793,7 +924,7 @@
std::vector<std::shared_ptr<TestLayer>> layers = {layer};
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
@@ -859,7 +990,7 @@
ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(),
{0, 0, getDisplayWidth(), getDisplayHeight()}, BLUE);
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -916,7 +1047,7 @@
ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), redRect, RED);
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
@@ -1026,7 +1157,7 @@
ReadbackHelper::fillColorsArea(expectedColors, getDisplayWidth(), dimmerRedRect, DIM_RED);
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(layers);
@@ -1162,7 +1293,7 @@
setExpectedColors(expectedColors);
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(mLayers);
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1207,7 +1338,7 @@
setExpectedColors(expectedColors);
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(mLayers);
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1247,7 +1378,7 @@
setExpectedColors(expectedColors);
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
writeLayers(mLayers);
ASSERT_TRUE(mReader.takeErrors().empty());
@@ -1321,7 +1452,7 @@
return;
}
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mLayer->setTransform(Transform::FLIP_H);
mLayer->setDataspace(ReadbackHelper::getDataspaceForColorMode(mode), *mWriter);
@@ -1366,7 +1497,7 @@
return;
}
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mLayer->setTransform(Transform::FLIP_V);
@@ -1411,7 +1542,7 @@
return;
}
ReadbackBuffer readbackBuffer(getPrimaryDisplayId(), mComposerClient, getDisplayWidth(),
- getDisplayHeight(), mPixelFormat, mDataspace);
+ getDisplayHeight(), mPixelFormat);
ASSERT_NO_FATAL_FAILURE(readbackBuffer.setReadbackBuffer());
mLayer->setTransform(Transform::ROT_180);
diff --git a/identity/aidl/Android.bp b/identity/aidl/Android.bp
index 2090473..6a25e62 100644
--- a/identity/aidl/Android.bp
+++ b/identity/aidl/Android.bp
@@ -18,7 +18,7 @@
"android.hardware.security.rkp-V3",
],
stability: "vintf",
- frozen: true,
+ frozen: false,
backend: {
java: {
platform_apis: true,
@@ -67,20 +67,20 @@
cc_defaults {
name: "identity_use_latest_hal_aidl_ndk_static",
static_libs: [
- "android.hardware.identity-V4-ndk",
+ "android.hardware.identity-V5-ndk",
],
}
cc_defaults {
name: "identity_use_latest_hal_aidl_ndk_shared",
shared_libs: [
- "android.hardware.identity-V4-ndk",
+ "android.hardware.identity-V5-ndk",
],
}
cc_defaults {
name: "identity_use_latest_hal_aidl_cpp_static",
static_libs: [
- "android.hardware.identity-V4-cpp",
+ "android.hardware.identity-V5-cpp",
],
}
diff --git a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl
index 5065641..4f2fe0b 100644
--- a/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl
+++ b/identity/aidl/aidl_api/android.hardware.identity/current/android/hardware/identity/IIdentityCredential.aidl
@@ -51,4 +51,5 @@
byte[] deleteCredentialWithChallenge(in byte[] challenge);
byte[] proveOwnership(in byte[] challenge);
android.hardware.identity.IWritableIdentityCredential updateCredential();
+ @SuppressWarnings(value={"out-array"}) void finishRetrievalWithSignature(out byte[] mac, out byte[] deviceNameSpaces, out byte[] ecdsaSignature);
}
diff --git a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
index 82b0a83..abdb00b 100644
--- a/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
+++ b/identity/aidl/android/hardware/identity/IIdentityCredential.aidl
@@ -194,7 +194,8 @@
* is permissible for this to be empty in which case the readerSignature parameter
* must also be empty. If this is not the case, the call fails with STATUS_FAILED.
*
- * If the SessionTranscript CBOR is not empty, the X and Y coordinates of the public
+ * If mdoc session encryption is used (e.g. createEphemeralKeyPair() has been called)
+ * and the SessionTranscript CBOR is not empty, the X and Y coordinates of the public
* part of the key-pair previously generated by createEphemeralKeyPair() must appear
* somewhere in the bytes of the CBOR. Each of these coordinates must appear encoded
* with the most significant bits first and use the exact amount of bits indicated by
@@ -239,8 +240,8 @@
* and remove the corresponding requests from the counts.
*/
void startRetrieval(in SecureAccessControlProfile[] accessControlProfiles,
- in HardwareAuthToken authToken, in byte[] itemsRequest, in byte[] signingKeyBlob,
- in byte[] sessionTranscript, in byte[] readerSignature, in int[] requestCounts);
+ in HardwareAuthToken authToken, in byte[] itemsRequest, in byte[] signingKeyBlob,
+ in byte[] sessionTranscript, in byte[] readerSignature, in int[] requestCounts);
/**
* Starts retrieving an entry, subject to access control requirements. Entries must be
@@ -271,8 +272,8 @@
* is given and this profile wasn't passed to startRetrieval() this call fails
* with STATUS_INVALID_DATA.
*/
- void startRetrieveEntryValue(in @utf8InCpp String nameSpace, in @utf8InCpp String name,
- in int entrySize, in int[] accessControlProfileIds);
+ void startRetrieveEntryValue(in @utf8InCpp String nameSpace,
+ in @utf8InCpp String name, in int entrySize, in int[] accessControlProfileIds);
/**
* Retrieves an entry value, or part of one, if the entry value is larger than gcmChunkSize.
@@ -293,11 +294,13 @@
* returned data.
*
* If signingKeyBlob or the sessionTranscript parameter passed to startRetrieval() is
- * empty then the returned MAC will be empty.
+ * empty or if mdoc session encryption is not being used (e.g. if createEphemeralKeyPair()
+ * was not called) then the returned MAC will be empty.
*
- * @param out mac is empty if signingKeyBlob or the sessionTranscript passed to
- * startRetrieval() is empty. Otherwise it is a COSE_Mac0 with empty payload
- * and the detached content is set to DeviceAuthenticationBytes as defined below.
+ * @param out mac is empty if signingKeyBlob, or the sessionTranscript passed to
+ * startRetrieval() is empty, or if mdoc session encryption is not being used (e.g. if
+ * createEphemeralKeyPair() was not called). Otherwise it is a COSE_Mac0 with empty
+ * payload and the detached content is set to DeviceAuthenticationBytes as defined below.
* This code is produced by using the key agreement and key derivation function
* from the ciphersuite with the authentication private key and the reader
* ephemeral public key to compute a shared message authentication code (MAC)
@@ -407,13 +410,13 @@
*/
void setRequestedNamespaces(in RequestNamespace[] requestNamespaces);
- /**
- * Sets the VerificationToken. This method must be called before startRetrieval() is
- * called. This token uses the same challenge as returned by createAuthChallenge().
- *
- * @param verificationToken
- * The verification token. This token is only valid if the timestamp field is non-zero.
- */
+ /**
+ * Sets the VerificationToken. This method must be called before startRetrieval() is
+ * called. This token uses the same challenge as returned by createAuthChallenge().
+ *
+ * @param verificationToken
+ * The verification token. This token is only valid if the timestamp field is non-zero.
+ */
void setVerificationToken(in VerificationToken verificationToken);
/**
@@ -485,4 +488,20 @@
* @return an IWritableIdentityCredential
*/
IWritableIdentityCredential updateCredential();
+
+ /**
+ * Like finishRetrieval() but also returns an ECDSA signature in addition to the MAC.
+ *
+ * See section 9.1.3.6 of ISO/IEC 18013-5:2021 for details of how the signature is calculated.
+ *
+ * Unlike MACing, an ECDSA signature will be returned even if mdoc session encryption isn't
+ * being used.
+ *
+ * This method was introduced in API version 5.
+ *
+ * @param ecdsaSignature a COSE_Sign1 signature described above.
+ */
+ @SuppressWarnings(value={"out-array"})
+ void finishRetrievalWithSignature(
+ out byte[] mac, out byte[] deviceNameSpaces, out byte[] ecdsaSignature);
}
diff --git a/identity/aidl/android/hardware/identity/IPresentationSession.aidl b/identity/aidl/android/hardware/identity/IPresentationSession.aidl
index b0449f0..0a06740 100644
--- a/identity/aidl/android/hardware/identity/IPresentationSession.aidl
+++ b/identity/aidl/android/hardware/identity/IPresentationSession.aidl
@@ -70,6 +70,17 @@
*
* This can be empty but if it's non-empty it must be valid CBOR.
*
+ * If mdoc session encryption is used (e.g. getEphemeralKeyPair() has been called)
+ * and the SessionTranscript CBOR is not empty, the X and Y coordinates of the public
+ * part of the key-pair previously generated by createEphemeralKeyPair() must appear
+ * somewhere in the bytes of the CBOR. Each of these coordinates must appear encoded
+ * with the most significant bits first and use the exact amount of bits indicated by
+ * the key size of the ephemeral keys. For example, if the ephemeral key is using the
+ * P-256 curve then the 32 bytes for the X coordinate encoded with the most significant
+ * bits first must appear somewhere in the CBOR and ditto for the 32 bytes for the Y
+ * coordinate. If this is not satisfied, the call fails with
+ * STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND.
+ *
* This method may only be called once per instance. If called more than once, STATUS_FAILED
* must be returned.
*
diff --git a/identity/aidl/default/FakeSecureHardwareProxy.cpp b/identity/aidl/default/FakeSecureHardwareProxy.cpp
index 9b9a749..8551ab7 100644
--- a/identity/aidl/default/FakeSecureHardwareProxy.cpp
+++ b/identity/aidl/default/FakeSecureHardwareProxy.cpp
@@ -596,10 +596,10 @@
return eicPresentationStartRetrieveEntries(&ctx_);
}
-bool FakeSecureHardwarePresentationProxy::calcMacKey(
+bool FakeSecureHardwarePresentationProxy::prepareDeviceAuthentication(
const vector<uint8_t>& sessionTranscript, const vector<uint8_t>& readerEphemeralPublicKey,
const vector<uint8_t>& signingKeyBlob, const string& docType,
- unsigned int numNamespacesWithValues, size_t expectedProofOfProvisioningSize) {
+ unsigned int numNamespacesWithValues, size_t expectedDeviceNamespacesSize) {
if (!validateId(__func__)) {
return false;
}
@@ -608,10 +608,10 @@
eicDebug("Unexpected size %zd of signingKeyBlob, expected 60", signingKeyBlob.size());
return false;
}
- return eicPresentationCalcMacKey(&ctx_, sessionTranscript.data(), sessionTranscript.size(),
- readerEphemeralPublicKey.data(), signingKeyBlob.data(),
- docType.c_str(), docType.size(), numNamespacesWithValues,
- expectedProofOfProvisioningSize);
+ return eicPresentationPrepareDeviceAuthentication(
+ &ctx_, sessionTranscript.data(), sessionTranscript.size(),
+ readerEphemeralPublicKey.data(), readerEphemeralPublicKey.size(), signingKeyBlob.data(),
+ docType.c_str(), docType.size(), numNamespacesWithValues, expectedDeviceNamespacesSize);
}
AccessCheckResult FakeSecureHardwarePresentationProxy::startRetrieveEntryValue(
@@ -673,6 +673,25 @@
return content;
}
+optional<pair<vector<uint8_t>, vector<uint8_t>>>
+FakeSecureHardwarePresentationProxy::finishRetrievalWithSignature() {
+ if (!validateId(__func__)) {
+ return std::nullopt;
+ }
+
+ vector<uint8_t> mac(32);
+ size_t macSize = 32;
+ vector<uint8_t> ecdsaSignature(EIC_ECDSA_P256_SIGNATURE_SIZE);
+ size_t ecdsaSignatureSize = EIC_ECDSA_P256_SIGNATURE_SIZE;
+ if (!eicPresentationFinishRetrievalWithSignature(&ctx_, mac.data(), &macSize,
+ ecdsaSignature.data(), &ecdsaSignatureSize)) {
+ return std::nullopt;
+ }
+ mac.resize(macSize);
+ ecdsaSignature.resize(ecdsaSignatureSize);
+ return std::make_pair(mac, ecdsaSignature);
+}
+
optional<vector<uint8_t>> FakeSecureHardwarePresentationProxy::finishRetrieval() {
if (!validateId(__func__)) {
return std::nullopt;
diff --git a/identity/aidl/default/FakeSecureHardwareProxy.h b/identity/aidl/default/FakeSecureHardwareProxy.h
index 2512074..b56ab93 100644
--- a/identity/aidl/default/FakeSecureHardwareProxy.h
+++ b/identity/aidl/default/FakeSecureHardwareProxy.h
@@ -175,11 +175,11 @@
const vector<uint8_t>& requestMessage, int coseSignAlg,
const vector<uint8_t>& readerSignatureOfToBeSigned) override;
- bool calcMacKey(const vector<uint8_t>& sessionTranscript,
- const vector<uint8_t>& readerEphemeralPublicKey,
- const vector<uint8_t>& signingKeyBlob, const string& docType,
- unsigned int numNamespacesWithValues,
- size_t expectedProofOfProvisioningSize) override;
+ bool prepareDeviceAuthentication(const vector<uint8_t>& sessionTranscript,
+ const vector<uint8_t>& readerEphemeralPublicKey,
+ const vector<uint8_t>& signingKeyBlob, const string& docType,
+ unsigned int numNamespacesWithValues,
+ size_t expectedDeviceNamespacesSize) override;
AccessCheckResult startRetrieveEntryValue(
const string& nameSpace, const string& name, unsigned int newNamespaceNumEntries,
@@ -191,6 +191,8 @@
optional<vector<uint8_t>> finishRetrieval() override;
+ optional<pair<vector<uint8_t>, vector<uint8_t>>> finishRetrievalWithSignature() override;
+
optional<vector<uint8_t>> deleteCredential(const string& docType,
const vector<uint8_t>& challenge,
bool includeChallenge,
diff --git a/identity/aidl/default/common/IdentityCredential.cpp b/identity/aidl/default/common/IdentityCredential.cpp
index ff80752..4c3b7b2 100644
--- a/identity/aidl/default/common/IdentityCredential.cpp
+++ b/identity/aidl/default/common/IdentityCredential.cpp
@@ -457,17 +457,16 @@
}
if (session_) {
- // If presenting in a session, the TA has already done this check.
-
+ // If presenting in a session, the TA has already done the check for (X, Y) as done
+ // below, see eicSessionSetSessionTranscript().
} else {
- // To prevent replay-attacks, we check that the public part of the ephemeral
- // key we previously created, is present in the DeviceEngagement part of
- // SessionTranscript as a COSE_Key, in uncompressed form.
+ // If mdoc session encryption is in use, check that the
+ // public part of the ephemeral key we previously created, is
+ // present in the DeviceEngagement part of SessionTranscript
+ // as a COSE_Key, in uncompressed form.
//
// We do this by just searching for the X and Y coordinates.
- //
- // Would be nice to move this check to the TA.
- if (sessionTranscript.size() > 0) {
+ if (sessionTranscript.size() > 0 && ephemeralPublicKey_.size() > 0) {
auto [getXYSuccess, ePubX, ePubY] = support::ecPublicKeyGetXandY(ephemeralPublicKey_);
if (!getXYSuccess) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
@@ -608,33 +607,36 @@
// Finally, pass info so the HMAC key can be derived and the TA can start
// creating the DeviceNameSpaces CBOR...
if (!session_) {
- if (sessionTranscript_.size() > 0 && readerPublicKey_.size() > 0 &&
- signingKeyBlob.size() > 0) {
- // We expect the reader ephemeral public key to be same size and curve
- // as the ephemeral key we generated (e.g. P-256 key), otherwise ECDH
- // won't work. So its length should be 65 bytes and it should be
- // starting with 0x04.
- if (readerPublicKey_.size() != 65 || readerPublicKey_[0] != 0x04) {
- return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
- IIdentityCredentialStore::STATUS_FAILED,
- "Reader public key is not in expected format"));
+ if (sessionTranscript_.size() > 0 && signingKeyBlob.size() > 0) {
+ vector<uint8_t> eReaderKeyP256;
+ if (readerPublicKey_.size() > 0) {
+ // If set, we expect the reader ephemeral public key to be same size and curve
+ // as the ephemeral key we generated (e.g. P-256 key), otherwise ECDH won't
+ // work. So its length should be 65 bytes and it should be starting with 0x04.
+ if (readerPublicKey_.size() != 65 || readerPublicKey_[0] != 0x04) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_FAILED,
+ "Reader public key is not in expected format"));
+ }
+ eReaderKeyP256 =
+ vector<uint8_t>(readerPublicKey_.begin() + 1, readerPublicKey_.end());
}
- vector<uint8_t> pubKeyP256(readerPublicKey_.begin() + 1, readerPublicKey_.end());
- if (!hwProxy_->calcMacKey(sessionTranscript_, pubKeyP256, signingKeyBlob, docType_,
- numNamespacesWithValues, expectedDeviceNameSpacesSize_)) {
+ if (!hwProxy_->prepareDeviceAuthentication(
+ sessionTranscript_, eReaderKeyP256, signingKeyBlob, docType_,
+ numNamespacesWithValues, expectedDeviceNameSpacesSize_)) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
IIdentityCredentialStore::STATUS_FAILED,
"Error starting retrieving entries"));
}
}
} else {
- if (session_->getSessionTranscript().size() > 0 &&
- session_->getReaderEphemeralPublicKey().size() > 0 && signingKeyBlob.size() > 0) {
+ if (session_->getSessionTranscript().size() > 0 && signingKeyBlob.size() > 0) {
// Don't actually pass the reader ephemeral public key in, the TA will get
// it from the session object.
//
- if (!hwProxy_->calcMacKey(sessionTranscript_, {}, signingKeyBlob, docType_,
- numNamespacesWithValues, expectedDeviceNameSpacesSize_)) {
+ if (!hwProxy_->prepareDeviceAuthentication(sessionTranscript_, {}, signingKeyBlob,
+ docType_, numNamespacesWithValues,
+ expectedDeviceNameSpacesSize_)) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
IIdentityCredentialStore::STATUS_FAILED,
"Error starting retrieving entries"));
@@ -924,8 +926,9 @@
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector<uint8_t>* outMac,
- vector<uint8_t>* outDeviceNameSpaces) {
+ndk::ScopedAStatus IdentityCredential::finishRetrievalWithSignature(
+ vector<uint8_t>* outMac, vector<uint8_t>* outDeviceNameSpaces,
+ vector<uint8_t>* outEcdsaSignature) {
ndk::ScopedAStatus status = ensureHwProxy();
if (!status.isOk()) {
return status;
@@ -948,17 +951,34 @@
.c_str()));
}
+ optional<vector<uint8_t>> digestToBeMaced;
+ optional<vector<uint8_t>> signatureToBeSigned;
+
+ // This relies on the fact that binder calls never pass a nullptr
+ // for out parameters. Hence if it's null here we know this was
+ // called from finishRetrieval() below.
+ if (outEcdsaSignature == nullptr) {
+ digestToBeMaced = hwProxy_->finishRetrieval();
+ if (!digestToBeMaced) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_INVALID_DATA,
+ "Error generating digestToBeMaced"));
+ }
+ } else {
+ auto macAndSignature = hwProxy_->finishRetrievalWithSignature();
+ if (!macAndSignature) {
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_INVALID_DATA,
+ "Error generating digestToBeMaced and signatureToBeSigned"));
+ }
+ digestToBeMaced = macAndSignature->first;
+ signatureToBeSigned = macAndSignature->second;
+ }
+
// If the TA calculated a MAC (it might not have), format it as a COSE_Mac0
//
- optional<vector<uint8_t>> mac;
- optional<vector<uint8_t>> digestToBeMaced = hwProxy_->finishRetrieval();
-
- // The MAC not being set means an error occurred.
- if (!digestToBeMaced) {
- return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
- IIdentityCredentialStore::STATUS_INVALID_DATA, "Error generating digestToBeMaced"));
- }
// Size 0 means that the MAC isn't set. If it's set, it has to be 32 bytes.
+ optional<vector<uint8_t>> mac;
if (digestToBeMaced.value().size() != 0) {
if (digestToBeMaced.value().size() != 32) {
return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
@@ -967,12 +987,27 @@
}
mac = support::coseMacWithDigest(digestToBeMaced.value(), {} /* data */);
}
-
*outMac = mac.value_or(vector<uint8_t>({}));
+
+ optional<vector<uint8_t>> signature;
+ if (signatureToBeSigned && signatureToBeSigned.value().size() != 0) {
+ signature = support::coseSignEcDsaWithSignature(signatureToBeSigned.value(), {}, // data
+ {}); // certificateChain
+ }
+ if (outEcdsaSignature != nullptr) {
+ *outEcdsaSignature = signature.value_or(vector<uint8_t>({}));
+ }
+
*outDeviceNameSpaces = encodedDeviceNameSpaces;
+
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus IdentityCredential::finishRetrieval(vector<uint8_t>* outMac,
+ vector<uint8_t>* outDeviceNameSpaces) {
+ return finishRetrievalWithSignature(outMac, outDeviceNameSpaces, nullptr);
+}
+
ndk::ScopedAStatus IdentityCredential::generateSigningKeyPair(
vector<uint8_t>* outSigningKeyBlob, Certificate* outSigningKeyCertificate) {
if (session_) {
diff --git a/identity/aidl/default/common/IdentityCredential.h b/identity/aidl/default/common/IdentityCredential.h
index 5929829..1e0cd64 100644
--- a/identity/aidl/default/common/IdentityCredential.h
+++ b/identity/aidl/default/common/IdentityCredential.h
@@ -92,6 +92,10 @@
ndk::ScopedAStatus updateCredential(
shared_ptr<IWritableIdentityCredential>* outWritableCredential) override;
+ ndk::ScopedAStatus finishRetrievalWithSignature(vector<uint8_t>* outMac,
+ vector<uint8_t>* outDeviceNameSpaces,
+ vector<uint8_t>* outEcdsaSignature) override;
+
private:
ndk::ScopedAStatus deleteCredentialCommon(const vector<uint8_t>& challenge,
bool includeChallenge,
diff --git a/identity/aidl/default/common/PresentationSession.cpp b/identity/aidl/default/common/PresentationSession.cpp
index 2eb7f2e..cf5b066 100644
--- a/identity/aidl/default/common/PresentationSession.cpp
+++ b/identity/aidl/default/common/PresentationSession.cpp
@@ -54,19 +54,6 @@
}
id_ = id.value();
- optional<vector<uint8_t>> ephemeralKeyPriv = hwProxy_->getEphemeralKeyPair();
- if (!ephemeralKeyPriv) {
- LOG(ERROR) << "Error getting ephemeral private key for session";
- return IIdentityCredentialStore::STATUS_FAILED;
- }
- optional<vector<uint8_t>> ephemeralKeyPair =
- support::ecPrivateKeyToKeyPair(ephemeralKeyPriv.value());
- if (!ephemeralKeyPair) {
- LOG(ERROR) << "Error creating ephemeral key-pair";
- return IIdentityCredentialStore::STATUS_FAILED;
- }
- ephemeralKeyPair_ = ephemeralKeyPair.value();
-
optional<uint64_t> authChallenge = hwProxy_->getAuthChallenge();
if (!authChallenge) {
LOG(ERROR) << "Error getting authChallenge for session";
@@ -78,6 +65,23 @@
}
ndk::ScopedAStatus PresentationSession::getEphemeralKeyPair(vector<uint8_t>* outKeyPair) {
+ if (ephemeralKeyPair_.size() == 0) {
+ optional<vector<uint8_t>> ephemeralKeyPriv = hwProxy_->getEphemeralKeyPair();
+ if (!ephemeralKeyPriv) {
+ LOG(ERROR) << "Error getting ephemeral private key for session";
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_FAILED,
+ "Error getting ephemeral private key for session"));
+ }
+ optional<vector<uint8_t>> ephemeralKeyPair =
+ support::ecPrivateKeyToKeyPair(ephemeralKeyPriv.value());
+ if (!ephemeralKeyPair) {
+ LOG(ERROR) << "Error creating ephemeral key-pair";
+ return ndk::ScopedAStatus(AStatus_fromServiceSpecificErrorWithMessage(
+ IIdentityCredentialStore::STATUS_FAILED, "Error creating ephemeral key-pair"));
+ }
+ ephemeralKeyPair_ = ephemeralKeyPair.value();
+ }
*outKeyPair = ephemeralKeyPair_;
return ndk::ScopedAStatus::ok();
}
diff --git a/identity/aidl/default/common/PresentationSession.h b/identity/aidl/default/common/PresentationSession.h
index 4cb174a..b3d46f9 100644
--- a/identity/aidl/default/common/PresentationSession.h
+++ b/identity/aidl/default/common/PresentationSession.h
@@ -72,9 +72,11 @@
// Set by initialize()
uint64_t id_;
- vector<uint8_t> ephemeralKeyPair_;
uint64_t authChallenge_;
+ // Set by getEphemeralKeyPair()
+ vector<uint8_t> ephemeralKeyPair_;
+
// Set by setReaderEphemeralPublicKey()
vector<uint8_t> readerPublicKey_;
diff --git a/identity/aidl/default/common/SecureHardwareProxy.h b/identity/aidl/default/common/SecureHardwareProxy.h
index 9f63ad8..6463318 100644
--- a/identity/aidl/default/common/SecureHardwareProxy.h
+++ b/identity/aidl/default/common/SecureHardwareProxy.h
@@ -194,11 +194,12 @@
const vector<uint8_t>& requestMessage, int coseSignAlg,
const vector<uint8_t>& readerSignatureOfToBeSigned) = 0;
- virtual bool calcMacKey(const vector<uint8_t>& sessionTranscript,
- const vector<uint8_t>& readerEphemeralPublicKey,
- const vector<uint8_t>& signingKeyBlob, const string& docType,
- unsigned int numNamespacesWithValues,
- size_t expectedProofOfProvisioningSize) = 0;
+ virtual bool prepareDeviceAuthentication(const vector<uint8_t>& sessionTranscript,
+ const vector<uint8_t>& readerEphemeralPublicKey,
+ const vector<uint8_t>& signingKeyBlob,
+ const string& docType,
+ unsigned int numNamespacesWithValues,
+ size_t expectedDeviceNamespacesSize) = 0;
virtual AccessCheckResult startRetrieveEntryValue(
const string& nameSpace, const string& name, unsigned int newNamespaceNumEntries,
@@ -209,6 +210,7 @@
const vector<int32_t>& accessControlProfileIds) = 0;
virtual optional<vector<uint8_t>> finishRetrieval();
+ virtual optional<pair<vector<uint8_t>, vector<uint8_t>>> finishRetrievalWithSignature();
virtual optional<vector<uint8_t>> deleteCredential(const string& docType,
const vector<uint8_t>& challenge,
diff --git a/identity/aidl/default/identity-default.xml b/identity/aidl/default/identity-default.xml
index cc0ddc7..d0d43af 100644
--- a/identity/aidl/default/identity-default.xml
+++ b/identity/aidl/default/identity-default.xml
@@ -1,7 +1,7 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.identity</name>
- <version>4</version>
+ <version>5</version>
<interface>
<name>IIdentityCredentialStore</name>
<instance>default</instance>
diff --git a/identity/aidl/default/libeic/EicPresentation.c b/identity/aidl/default/libeic/EicPresentation.c
index 104a559..23fd0b3 100644
--- a/identity/aidl/default/libeic/EicPresentation.c
+++ b/identity/aidl/default/libeic/EicPresentation.c
@@ -557,87 +557,11 @@
return true;
}
-bool eicPresentationCalcMacKey(EicPresentation* ctx, const uint8_t* sessionTranscript,
- size_t sessionTranscriptSize,
- const uint8_t readerEphemeralPublicKey[EIC_P256_PUB_KEY_SIZE],
- const uint8_t signingKeyBlob[60], const char* docType,
- size_t docTypeLength, unsigned int numNamespacesWithValues,
- size_t expectedDeviceNamespacesSize) {
- if (ctx->sessionId != 0) {
- EicSession* session = eicSessionGetForId(ctx->sessionId);
- if (session == NULL) {
- eicDebug("Error looking up session for sessionId %" PRIu32, ctx->sessionId);
- return false;
- }
- EicSha256Ctx sha256;
- uint8_t sessionTranscriptSha256[EIC_SHA256_DIGEST_SIZE];
- eicOpsSha256Init(&sha256);
- eicOpsSha256Update(&sha256, sessionTranscript, sessionTranscriptSize);
- eicOpsSha256Final(&sha256, sessionTranscriptSha256);
- if (eicCryptoMemCmp(sessionTranscriptSha256, session->sessionTranscriptSha256,
- EIC_SHA256_DIGEST_SIZE) != 0) {
- eicDebug("SessionTranscript mismatch");
- return false;
- }
- readerEphemeralPublicKey = session->readerEphemeralPublicKey;
- }
-
- uint8_t signingKeyPriv[EIC_P256_PRIV_KEY_SIZE];
- if (!eicOpsDecryptAes128Gcm(ctx->storageKey, signingKeyBlob, 60, (const uint8_t*)docType,
- docTypeLength, signingKeyPriv)) {
- eicDebug("Error decrypting signingKeyBlob");
- return false;
- }
-
- uint8_t sharedSecret[EIC_P256_COORDINATE_SIZE];
- if (!eicOpsEcdh(readerEphemeralPublicKey, signingKeyPriv, sharedSecret)) {
- eicDebug("ECDH failed");
- return false;
- }
-
- EicCbor cbor;
- eicCborInit(&cbor, NULL, 0);
- eicCborAppendSemantic(&cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
- eicCborAppendByteString(&cbor, sessionTranscript, sessionTranscriptSize);
- uint8_t salt[EIC_SHA256_DIGEST_SIZE];
- eicCborFinal(&cbor, salt);
-
- const uint8_t info[7] = {'E', 'M', 'a', 'c', 'K', 'e', 'y'};
- uint8_t derivedKey[32];
- if (!eicOpsHkdf(sharedSecret, EIC_P256_COORDINATE_SIZE, salt, sizeof(salt), info, sizeof(info),
- derivedKey, sizeof(derivedKey))) {
- eicDebug("HKDF failed");
- return false;
- }
-
- eicCborInitHmacSha256(&ctx->cbor, NULL, 0, derivedKey, sizeof(derivedKey));
- ctx->buildCbor = true;
-
- // What we're going to calculate the HMAC-SHA256 is the COSE ToBeMaced
- // structure which looks like the following:
- //
- // MAC_structure = [
- // context : "MAC" / "MAC0",
- // protected : empty_or_serialized_map,
- // external_aad : bstr,
- // payload : bstr
- // ]
- //
- eicCborAppendArray(&ctx->cbor, 4);
- eicCborAppendStringZ(&ctx->cbor, "MAC0");
-
- // The COSE Encoded protected headers is just a single field with
- // COSE_LABEL_ALG (1) -> COSE_ALG_HMAC_256_256 (5). For simplicitly we just
- // hard-code the CBOR encoding:
- static const uint8_t coseEncodedProtectedHeaders[] = {0xa1, 0x01, 0x05};
- eicCborAppendByteString(&ctx->cbor, coseEncodedProtectedHeaders,
- sizeof(coseEncodedProtectedHeaders));
-
- // We currently don't support Externally Supplied Data (RFC 8152 section 4.3)
- // so external_aad is the empty bstr
- static const uint8_t externalAad[0] = {};
- eicCborAppendByteString(&ctx->cbor, externalAad, sizeof(externalAad));
-
+// Helper used to append the DeviceAuthencation prelude, used for both MACing and ECDSA signing.
+static size_t appendDeviceAuthentication(EicCbor* cbor, const uint8_t* sessionTranscript,
+ size_t sessionTranscriptSize, const char* docType,
+ size_t docTypeLength,
+ size_t expectedDeviceNamespacesSize) {
// For the payload, the _encoded_ form follows here. We handle this by simply
// opening a bstr, and then writing the CBOR. This requires us to know the
// size of said bstr, ahead of time... the CBOR to be written is
@@ -674,26 +598,148 @@
dabCalculatedSize += calculatedSize;
// Begin the bytestring for DeviceAuthenticationBytes;
- eicCborBegin(&ctx->cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, dabCalculatedSize);
+ eicCborBegin(cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, dabCalculatedSize);
- eicCborAppendSemantic(&ctx->cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
+ eicCborAppendSemantic(cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
// Begins the bytestring for DeviceAuthentication;
- eicCborBegin(&ctx->cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, calculatedSize);
+ eicCborBegin(cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, calculatedSize);
- eicCborAppendArray(&ctx->cbor, 4);
- eicCborAppendStringZ(&ctx->cbor, "DeviceAuthentication");
- eicCborAppend(&ctx->cbor, sessionTranscript, sessionTranscriptSize);
- eicCborAppendString(&ctx->cbor, docType, docTypeLength);
+ eicCborAppendArray(cbor, 4);
+ eicCborAppendStringZ(cbor, "DeviceAuthentication");
+ eicCborAppend(cbor, sessionTranscript, sessionTranscriptSize);
+ eicCborAppendString(cbor, docType, docTypeLength);
// For the payload, the _encoded_ form follows here. We handle this by simply
// opening a bstr, and then writing the CBOR. This requires us to know the
// size of said bstr, ahead of time.
- eicCborAppendSemantic(&ctx->cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
- eicCborBegin(&ctx->cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, expectedDeviceNamespacesSize);
- ctx->expectedCborSizeAtEnd = expectedDeviceNamespacesSize + ctx->cbor.size;
+ eicCborAppendSemantic(cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
+ eicCborBegin(cbor, EIC_CBOR_MAJOR_TYPE_BYTE_STRING, expectedDeviceNamespacesSize);
+ size_t expectedCborSizeAtEnd = expectedDeviceNamespacesSize + cbor->size;
- eicCborAppendMap(&ctx->cbor, numNamespacesWithValues);
+ return expectedCborSizeAtEnd;
+}
+
+bool eicPresentationPrepareDeviceAuthentication(
+ EicPresentation* ctx, const uint8_t* sessionTranscript, size_t sessionTranscriptSize,
+ const uint8_t* readerEphemeralPublicKey, size_t readerEphemeralPublicKeySize,
+ const uint8_t signingKeyBlob[60], const char* docType, size_t docTypeLength,
+ unsigned int numNamespacesWithValues, size_t expectedDeviceNamespacesSize) {
+ if (ctx->sessionId != 0) {
+ if (readerEphemeralPublicKeySize != 0) {
+ eicDebug("In a session but readerEphemeralPublicKeySize is non-zero");
+ return false;
+ }
+ EicSession* session = eicSessionGetForId(ctx->sessionId);
+ if (session == NULL) {
+ eicDebug("Error looking up session for sessionId %" PRIu32, ctx->sessionId);
+ return false;
+ }
+ EicSha256Ctx sha256;
+ uint8_t sessionTranscriptSha256[EIC_SHA256_DIGEST_SIZE];
+ eicOpsSha256Init(&sha256);
+ eicOpsSha256Update(&sha256, sessionTranscript, sessionTranscriptSize);
+ eicOpsSha256Final(&sha256, sessionTranscriptSha256);
+ if (eicCryptoMemCmp(sessionTranscriptSha256, session->sessionTranscriptSha256,
+ EIC_SHA256_DIGEST_SIZE) != 0) {
+ eicDebug("SessionTranscript mismatch");
+ return false;
+ }
+ readerEphemeralPublicKey = session->readerEphemeralPublicKey;
+ readerEphemeralPublicKeySize = session->readerEphemeralPublicKeySize;
+ }
+
+ // Stash the decrypted DeviceKey in context since we'll need it later in
+ // eicPresentationFinishRetrievalWithSignature()
+ if (!eicOpsDecryptAes128Gcm(ctx->storageKey, signingKeyBlob, 60, (const uint8_t*)docType,
+ docTypeLength, ctx->deviceKeyPriv)) {
+ eicDebug("Error decrypting signingKeyBlob");
+ return false;
+ }
+
+ // We can only do MACing if EReaderKey has been set... it might not have been set if for
+ // example mdoc session encryption isn't in use. In that case we can still do ECDSA
+ if (readerEphemeralPublicKeySize > 0) {
+ if (readerEphemeralPublicKeySize != EIC_P256_PUB_KEY_SIZE) {
+ eicDebug("Unexpected size %zd for readerEphemeralPublicKeySize",
+ readerEphemeralPublicKeySize);
+ return false;
+ }
+
+ uint8_t sharedSecret[EIC_P256_COORDINATE_SIZE];
+ if (!eicOpsEcdh(readerEphemeralPublicKey, ctx->deviceKeyPriv, sharedSecret)) {
+ eicDebug("ECDH failed");
+ return false;
+ }
+
+ EicCbor cbor;
+ eicCborInit(&cbor, NULL, 0);
+ eicCborAppendSemantic(&cbor, EIC_CBOR_SEMANTIC_TAG_ENCODED_CBOR);
+ eicCborAppendByteString(&cbor, sessionTranscript, sessionTranscriptSize);
+ uint8_t salt[EIC_SHA256_DIGEST_SIZE];
+ eicCborFinal(&cbor, salt);
+
+ const uint8_t info[7] = {'E', 'M', 'a', 'c', 'K', 'e', 'y'};
+ uint8_t derivedKey[32];
+ if (!eicOpsHkdf(sharedSecret, EIC_P256_COORDINATE_SIZE, salt, sizeof(salt), info,
+ sizeof(info), derivedKey, sizeof(derivedKey))) {
+ eicDebug("HKDF failed");
+ return false;
+ }
+
+ eicCborInitHmacSha256(&ctx->cbor, NULL, 0, derivedKey, sizeof(derivedKey));
+
+ // What we're going to calculate the HMAC-SHA256 is the COSE ToBeMaced
+ // structure which looks like the following:
+ //
+ // MAC_structure = [
+ // context : "MAC" / "MAC0",
+ // protected : empty_or_serialized_map,
+ // external_aad : bstr,
+ // payload : bstr
+ // ]
+ //
+ eicCborAppendArray(&ctx->cbor, 4);
+ eicCborAppendStringZ(&ctx->cbor, "MAC0");
+
+ // The COSE Encoded protected headers is just a single field with
+ // COSE_LABEL_ALG (1) -> COSE_ALG_HMAC_256_256 (5). For simplicitly we just
+ // hard-code the CBOR encoding:
+ static const uint8_t coseEncodedProtectedHeaders[] = {0xa1, 0x01, 0x05};
+ eicCborAppendByteString(&ctx->cbor, coseEncodedProtectedHeaders,
+ sizeof(coseEncodedProtectedHeaders));
+
+ // We currently don't support Externally Supplied Data (RFC 8152 section 4.3)
+ // so external_aad is the empty bstr
+ static const uint8_t externalAad[0] = {};
+ eicCborAppendByteString(&ctx->cbor, externalAad, sizeof(externalAad));
+
+ // Append DeviceAuthentication prelude and open the DeviceSigned map...
+ ctx->expectedCborSizeAtEnd =
+ appendDeviceAuthentication(&ctx->cbor, sessionTranscript, sessionTranscriptSize,
+ docType, docTypeLength, expectedDeviceNamespacesSize);
+ eicCborAppendMap(&ctx->cbor, numNamespacesWithValues);
+ ctx->buildCbor = true;
+ }
+
+ // Now do the same for ECDSA signatures...
+ //
+ eicCborInit(&ctx->cborEcdsa, NULL, 0);
+ eicCborAppendArray(&ctx->cborEcdsa, 4);
+ eicCborAppendStringZ(&ctx->cborEcdsa, "Signature1");
+ static const uint8_t coseEncodedProtectedHeadersEcdsa[] = {0xa1, 0x01, 0x26};
+ eicCborAppendByteString(&ctx->cborEcdsa, coseEncodedProtectedHeadersEcdsa,
+ sizeof(coseEncodedProtectedHeadersEcdsa));
+ static const uint8_t externalAadEcdsa[0] = {};
+ eicCborAppendByteString(&ctx->cborEcdsa, externalAadEcdsa, sizeof(externalAadEcdsa));
+
+ // Append DeviceAuthentication prelude and open the DeviceSigned map...
+ ctx->expectedCborEcdsaSizeAtEnd =
+ appendDeviceAuthentication(&ctx->cborEcdsa, sessionTranscript, sessionTranscriptSize,
+ docType, docTypeLength, expectedDeviceNamespacesSize);
+ eicCborAppendMap(&ctx->cborEcdsa, numNamespacesWithValues);
+ ctx->buildCborEcdsa = true;
+
return true;
}
@@ -702,6 +748,7 @@
// state objects here.
ctx->requestMessageValidated = false;
ctx->buildCbor = false;
+ ctx->buildCborEcdsa = false;
ctx->accessControlProfileMaskValidated = 0;
ctx->accessControlProfileMaskUsesReaderAuth = 0;
ctx->accessControlProfileMaskFailedReaderAuth = 0;
@@ -724,6 +771,9 @@
if (newNamespaceNumEntries > 0) {
eicCborAppendString(&ctx->cbor, nameSpace, nameSpaceLength);
eicCborAppendMap(&ctx->cbor, newNamespaceNumEntries);
+
+ eicCborAppendString(&ctx->cborEcdsa, nameSpace, nameSpaceLength);
+ eicCborAppendMap(&ctx->cborEcdsa, newNamespaceNumEntries);
}
// We'll need to calc and store a digest of additionalData to check that it's the same
@@ -778,6 +828,7 @@
if (result == EIC_ACCESS_CHECK_RESULT_OK) {
eicCborAppendString(&ctx->cbor, name, nameLength);
+ eicCborAppendString(&ctx->cborEcdsa, name, nameLength);
ctx->accessCheckOk = true;
}
return result;
@@ -821,6 +872,7 @@
}
eicCborAppend(&ctx->cbor, content, encryptedContentSize - 28);
+ eicCborAppend(&ctx->cborEcdsa, content, encryptedContentSize - 28);
return true;
}
@@ -842,6 +894,40 @@
return false;
}
eicCborFinal(&ctx->cbor, digestToBeMaced);
+
+ return true;
+}
+
+bool eicPresentationFinishRetrievalWithSignature(EicPresentation* ctx, uint8_t* digestToBeMaced,
+ size_t* digestToBeMacedSize,
+ uint8_t* signatureOfToBeSigned,
+ size_t* signatureOfToBeSignedSize) {
+ if (!eicPresentationFinishRetrieval(ctx, digestToBeMaced, digestToBeMacedSize)) {
+ return false;
+ }
+
+ if (!ctx->buildCborEcdsa) {
+ *signatureOfToBeSignedSize = 0;
+ return true;
+ }
+ if (*signatureOfToBeSignedSize != EIC_ECDSA_P256_SIGNATURE_SIZE) {
+ return false;
+ }
+
+ // This verifies that the correct expectedDeviceNamespacesSize value was
+ // passed in at eicPresentationCalcMacKey() time.
+ if (ctx->cborEcdsa.size != ctx->expectedCborEcdsaSizeAtEnd) {
+ eicDebug("CBOR ECDSA size is %zd, was expecting %zd", ctx->cborEcdsa.size,
+ ctx->expectedCborEcdsaSizeAtEnd);
+ return false;
+ }
+ uint8_t cborSha256[EIC_SHA256_DIGEST_SIZE];
+ eicCborFinal(&ctx->cborEcdsa, cborSha256);
+ if (!eicOpsEcDsa(ctx->deviceKeyPriv, cborSha256, signatureOfToBeSigned)) {
+ eicDebug("Error signing DeviceAuthentication");
+ return false;
+ }
+ eicDebug("set the signature");
return true;
}
diff --git a/identity/aidl/default/libeic/EicPresentation.h b/identity/aidl/default/libeic/EicPresentation.h
index a031890..cd3162a 100644
--- a/identity/aidl/default/libeic/EicPresentation.h
+++ b/identity/aidl/default/libeic/EicPresentation.h
@@ -76,6 +76,7 @@
// aren't.
bool requestMessageValidated;
bool buildCbor;
+ bool buildCborEcdsa;
// Set to true initialized as a test credential.
bool testCredential;
@@ -101,6 +102,12 @@
size_t expectedCborSizeAtEnd;
EicCbor cbor;
+
+ // The selected DeviceKey / AuthKey
+ uint8_t deviceKeyPriv[EIC_P256_PRIV_KEY_SIZE];
+
+ EicCbor cborEcdsa;
+ size_t expectedCborEcdsaSizeAtEnd;
} EicPresentation;
// If sessionId is zero (EIC_PRESENTATION_ID_UNSET), the presentation object is not associated
@@ -214,14 +221,13 @@
EIC_ACCESS_CHECK_RESULT_READER_AUTHENTICATION_FAILED,
} EicAccessCheckResult;
-// Passes enough information to calculate the MACing key
+// Passes enough information to calculate the MACing key and/or prepare ECDSA signing
//
-bool eicPresentationCalcMacKey(EicPresentation* ctx, const uint8_t* sessionTranscript,
- size_t sessionTranscriptSize,
- const uint8_t readerEphemeralPublicKey[EIC_P256_PUB_KEY_SIZE],
- const uint8_t signingKeyBlob[60], const char* docType,
- size_t docTypeLength, unsigned int numNamespacesWithValues,
- size_t expectedDeviceNamespacesSize);
+bool eicPresentationPrepareDeviceAuthentication(
+ EicPresentation* ctx, const uint8_t* sessionTranscript, size_t sessionTranscriptSize,
+ const uint8_t* readerEphemeralPublicKey, size_t readerEphemeralPublicKeySize,
+ const uint8_t signingKeyBlob[60], const char* docType, size_t docTypeLength,
+ unsigned int numNamespacesWithValues, size_t expectedDeviceNamespacesSize);
// The scratchSpace should be set to a buffer at least 512 bytes (ideally 1024
// bytes, the bigger the better). It's done this way to avoid allocating stack
@@ -253,6 +259,13 @@
bool eicPresentationFinishRetrieval(EicPresentation* ctx, uint8_t* digestToBeMaced,
size_t* digestToBeMacedSize);
+// Like eicPresentationFinishRetrieval() but also returns an ECDSA signature.
+//
+bool eicPresentationFinishRetrievalWithSignature(EicPresentation* ctx, uint8_t* digestToBeMaced,
+ size_t* digestToBeMacedSize,
+ uint8_t* signatureOfToBeSigned,
+ size_t* signatureOfToBeSignedSize);
+
// The data returned in |signatureOfToBeSigned| contains the ECDSA signature of
// the ToBeSigned CBOR from RFC 8051 "4.4. Signing and Verification Process"
// where content is set to the ProofOfDeletion CBOR.
diff --git a/identity/aidl/default/libeic/EicSession.c b/identity/aidl/default/libeic/EicSession.c
index d0c7a0d..e44fa68 100644
--- a/identity/aidl/default/libeic/EicSession.c
+++ b/identity/aidl/default/libeic/EicSession.c
@@ -84,30 +84,35 @@
bool eicSessionGetEphemeralKeyPair(EicSession* ctx,
uint8_t ephemeralPrivateKey[EIC_P256_PRIV_KEY_SIZE]) {
eicMemCpy(ephemeralPrivateKey, ctx->ephemeralPrivateKey, EIC_P256_PRIV_KEY_SIZE);
+ ctx->getEphemeralKeyPairCalled = true;
return true;
}
bool eicSessionSetReaderEphemeralPublicKey(
EicSession* ctx, const uint8_t readerEphemeralPublicKey[EIC_P256_PUB_KEY_SIZE]) {
eicMemCpy(ctx->readerEphemeralPublicKey, readerEphemeralPublicKey, EIC_P256_PUB_KEY_SIZE);
+ ctx->readerEphemeralPublicKeySize = EIC_P256_PUB_KEY_SIZE;
return true;
}
bool eicSessionSetSessionTranscript(EicSession* ctx, const uint8_t* sessionTranscript,
size_t sessionTranscriptSize) {
- // Only accept the SessionTranscript if X and Y from the ephemeral key
- // we created is somewhere in SessionTranscript...
+ // If mdoc session encryption is in use, only accept the
+ // SessionTranscript if X and Y from the ephemeral key we created
+ // is somewhere in SessionTranscript...
//
- if (eicMemMem(sessionTranscript, sessionTranscriptSize, ctx->ephemeralPublicKey,
- EIC_P256_PUB_KEY_SIZE / 2) == NULL) {
- eicDebug("Error finding X from ephemeralPublicKey in sessionTranscript");
- return false;
- }
- if (eicMemMem(sessionTranscript, sessionTranscriptSize,
- ctx->ephemeralPublicKey + EIC_P256_PUB_KEY_SIZE / 2,
- EIC_P256_PUB_KEY_SIZE / 2) == NULL) {
- eicDebug("Error finding Y from ephemeralPublicKey in sessionTranscript");
- return false;
+ if (ctx->getEphemeralKeyPairCalled) {
+ if (eicMemMem(sessionTranscript, sessionTranscriptSize, ctx->ephemeralPublicKey,
+ EIC_P256_PUB_KEY_SIZE / 2) == NULL) {
+ eicDebug("Error finding X from ephemeralPublicKey in sessionTranscript");
+ return false;
+ }
+ if (eicMemMem(sessionTranscript, sessionTranscriptSize,
+ ctx->ephemeralPublicKey + EIC_P256_PUB_KEY_SIZE / 2,
+ EIC_P256_PUB_KEY_SIZE / 2) == NULL) {
+ eicDebug("Error finding Y from ephemeralPublicKey in sessionTranscript");
+ return false;
+ }
}
// To save space we only store the SHA-256 of SessionTranscript
diff --git a/identity/aidl/default/libeic/EicSession.h b/identity/aidl/default/libeic/EicSession.h
index 0303dae..ae9babf 100644
--- a/identity/aidl/default/libeic/EicSession.h
+++ b/identity/aidl/default/libeic/EicSession.h
@@ -31,6 +31,9 @@
// A non-zero number unique for this EicSession instance
uint32_t id;
+ // Set to true iff eicSessionGetEphemeralKeyPair() has been called.
+ bool getEphemeralKeyPairCalled;
+
// The challenge generated at construction time by eicSessionInit().
uint64_t authChallenge;
@@ -41,6 +44,7 @@
uint8_t sessionTranscriptSha256[EIC_SHA256_DIGEST_SIZE];
+ size_t readerEphemeralPublicKeySize;
} EicSession;
bool eicSessionInit(EicSession* ctx);
diff --git a/identity/aidl/vts/EndToEndTests.cpp b/identity/aidl/vts/EndToEndTests.cpp
index 67db915..ae9035b 100644
--- a/identity/aidl/vts/EndToEndTests.cpp
+++ b/identity/aidl/vts/EndToEndTests.cpp
@@ -441,8 +441,18 @@
}
vector<uint8_t> mac;
+ vector<uint8_t> ecdsaSignature;
vector<uint8_t> deviceNameSpacesEncoded;
- ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+ // API version 5 (feature version 202301) returns both MAC and ECDSA signature.
+ if (halApiVersion_ >= 5) {
+ ASSERT_TRUE(credential
+ ->finishRetrievalWithSignature(&mac, &deviceNameSpacesEncoded,
+ &ecdsaSignature)
+ .isOk());
+ ASSERT_GT(ecdsaSignature.size(), 0);
+ } else {
+ ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+ }
cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
ASSERT_EQ(
"{\n"
@@ -475,6 +485,21 @@
ASSERT_TRUE(calculatedMac);
EXPECT_EQ(mac, calculatedMac);
+ if (ecdsaSignature.size() > 0) {
+ vector<uint8_t> encodedDeviceAuthentication =
+ cppbor::Array()
+ .add("DeviceAuthentication")
+ .add(sessionTranscript.clone())
+ .add(docType)
+ .add(cppbor::SemanticTag(24, deviceNameSpacesEncoded))
+ .encode();
+ vector<uint8_t> deviceAuthenticationBytes =
+ cppbor::SemanticTag(24, encodedDeviceAuthentication).encode();
+ EXPECT_TRUE(support::coseCheckEcDsaSignature(ecdsaSignature,
+ deviceAuthenticationBytes, // Detached content
+ signingPubKey.value()));
+ }
+
// Also perform an additional empty request. This is what mDL applications
// are envisioned to do - one call to get the data elements, another to get
// an empty DeviceSignedItems and corresponding MAC.
@@ -486,7 +511,16 @@
signingKeyBlob, sessionTranscriptEncoded, {}, // readerSignature,
testEntriesEntryCounts)
.isOk());
- ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+ // API version 5 (feature version 202301) returns both MAC and ECDSA signature.
+ if (halApiVersion_ >= 5) {
+ ASSERT_TRUE(credential
+ ->finishRetrievalWithSignature(&mac, &deviceNameSpacesEncoded,
+ &ecdsaSignature)
+ .isOk());
+ ASSERT_GT(ecdsaSignature.size(), 0);
+ } else {
+ ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+ }
cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
ASSERT_EQ("{}", cborPretty);
// Calculate DeviceAuthentication and MAC (MACing key hasn't changed)
@@ -497,6 +531,21 @@
ASSERT_TRUE(calculatedMac);
EXPECT_EQ(mac, calculatedMac);
+ if (ecdsaSignature.size() > 0) {
+ vector<uint8_t> encodedDeviceAuthentication =
+ cppbor::Array()
+ .add("DeviceAuthentication")
+ .add(sessionTranscript.clone())
+ .add(docType)
+ .add(cppbor::SemanticTag(24, deviceNameSpacesEncoded))
+ .encode();
+ vector<uint8_t> deviceAuthenticationBytes =
+ cppbor::SemanticTag(24, encodedDeviceAuthentication).encode();
+ EXPECT_TRUE(support::coseCheckEcDsaSignature(ecdsaSignature,
+ deviceAuthenticationBytes, // Detached content
+ signingPubKey.value()));
+ }
+
// Some mDL apps might send a request but with a single empty
// namespace. Check that too.
RequestNamespace emptyRequestNS;
@@ -508,7 +557,16 @@
signingKeyBlob, sessionTranscriptEncoded, {}, // readerSignature,
testEntriesEntryCounts)
.isOk());
- ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+ // API version 5 (feature version 202301) returns both MAC and ECDSA signature.
+ if (halApiVersion_ >= 5) {
+ ASSERT_TRUE(credential
+ ->finishRetrievalWithSignature(&mac, &deviceNameSpacesEncoded,
+ &ecdsaSignature)
+ .isOk());
+ ASSERT_GT(ecdsaSignature.size(), 0);
+ } else {
+ ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
+ }
cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
ASSERT_EQ("{}", cborPretty);
// Calculate DeviceAuthentication and MAC (MACing key hasn't changed)
@@ -518,6 +576,248 @@
eMacKey.value()); // EMacKey
ASSERT_TRUE(calculatedMac);
EXPECT_EQ(mac, calculatedMac);
+
+ if (ecdsaSignature.size() > 0) {
+ vector<uint8_t> encodedDeviceAuthentication =
+ cppbor::Array()
+ .add("DeviceAuthentication")
+ .add(sessionTranscript.clone())
+ .add(docType)
+ .add(cppbor::SemanticTag(24, deviceNameSpacesEncoded))
+ .encode();
+ vector<uint8_t> deviceAuthenticationBytes =
+ cppbor::SemanticTag(24, encodedDeviceAuthentication).encode();
+ EXPECT_TRUE(support::coseCheckEcDsaSignature(ecdsaSignature,
+ deviceAuthenticationBytes, // Detached content
+ signingPubKey.value()));
+ }
+}
+
+TEST_P(EndToEndTests, noSessionEncryption) {
+ if (halApiVersion_ < 5) {
+ GTEST_SKIP() << "Need HAL API version 5, have " << halApiVersion_;
+ }
+
+ const vector<test_utils::TestProfile> testProfiles = {// Profile 0 (no authentication)
+ {0, {}, false, 0}};
+
+ HardwareAuthToken authToken;
+ VerificationToken verificationToken;
+ authToken.challenge = 0;
+ authToken.userId = 0;
+ authToken.authenticatorId = 0;
+ authToken.authenticatorType = ::android::hardware::keymaster::HardwareAuthenticatorType::NONE;
+ authToken.timestamp.milliSeconds = 0;
+ authToken.mac.clear();
+ verificationToken.challenge = 0;
+ verificationToken.timestamp.milliSeconds = 0;
+ verificationToken.securityLevel = ::android::hardware::keymaster::SecurityLevel::SOFTWARE;
+ verificationToken.mac.clear();
+
+ // Here's the actual test data:
+ const vector<test_utils::TestEntryData> testEntries = {
+ {"PersonalData", "Last name", string("Turing"), vector<int32_t>{0}},
+ {"PersonalData", "Birth date", string("19120623"), vector<int32_t>{0}},
+ {"PersonalData", "First name", string("Alan"), vector<int32_t>{0}},
+ };
+ const vector<int32_t> testEntriesEntryCounts = {3};
+ HardwareInformation hwInfo;
+ ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());
+
+ string cborPretty;
+ sp<IWritableIdentityCredential> writableCredential;
+ ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_,
+ true /* testCredential */));
+
+ string challenge = "attestationChallenge";
+ test_utils::AttestationData attData(writableCredential, challenge,
+ {1} /* atteestationApplicationId */);
+ ASSERT_TRUE(attData.result.isOk())
+ << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
+
+ // This is kinda of a hack but we need to give the size of
+ // ProofOfProvisioning that we'll expect to receive.
+ const int32_t expectedProofOfProvisioningSize = 230;
+ // OK to fail, not available in v1 HAL
+ writableCredential->setExpectedProofOfProvisioningSize(expectedProofOfProvisioningSize);
+ ASSERT_TRUE(
+ writableCredential->startPersonalization(testProfiles.size(), testEntriesEntryCounts)
+ .isOk());
+
+ optional<vector<SecureAccessControlProfile>> secureProfiles =
+ test_utils::addAccessControlProfiles(writableCredential, testProfiles);
+ ASSERT_TRUE(secureProfiles);
+
+ // Uses TestEntryData* pointer as key and values are the encrypted blobs. This
+ // is a little hacky but it works well enough.
+ map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;
+
+ for (const auto& entry : testEntries) {
+ ASSERT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
+ encryptedBlobs, true));
+ }
+
+ vector<uint8_t> credentialData;
+ vector<uint8_t> proofOfProvisioningSignature;
+ ASSERT_TRUE(
+ writableCredential->finishAddingEntries(&credentialData, &proofOfProvisioningSignature)
+ .isOk());
+
+ // Validate the proofOfProvisioning which was returned
+ optional<vector<uint8_t>> proofOfProvisioning =
+ support::coseSignGetPayload(proofOfProvisioningSignature);
+ ASSERT_TRUE(proofOfProvisioning);
+ cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"});
+ EXPECT_EQ(
+ "[\n"
+ " 'ProofOfProvisioning',\n"
+ " 'org.iso.18013-5.2019.mdl',\n"
+ " [\n"
+ " {\n"
+ " 'id' : 0,\n"
+ " },\n"
+ " ],\n"
+ " {\n"
+ " 'PersonalData' : [\n"
+ " {\n"
+ " 'name' : 'Last name',\n"
+ " 'value' : 'Turing',\n"
+ " 'accessControlProfiles' : [0, ],\n"
+ " },\n"
+ " {\n"
+ " 'name' : 'Birth date',\n"
+ " 'value' : '19120623',\n"
+ " 'accessControlProfiles' : [0, ],\n"
+ " },\n"
+ " {\n"
+ " 'name' : 'First name',\n"
+ " 'value' : 'Alan',\n"
+ " 'accessControlProfiles' : [0, ],\n"
+ " },\n"
+ " ],\n"
+ " },\n"
+ " true,\n"
+ "]",
+ cborPretty);
+
+ optional<vector<uint8_t>> credentialPubKey = support::certificateChainGetTopMostKey(
+ attData.attestationCertificate[0].encodedCertificate);
+ ASSERT_TRUE(credentialPubKey);
+ EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfProvisioningSignature,
+ {}, // Additional data
+ credentialPubKey.value()));
+ writableCredential = nullptr;
+
+ // Extract doctype, storage key, and credentialPrivKey from credentialData... this works
+ // only because we asked for a test-credential meaning that the HBK is all zeroes.
+ auto [exSuccess, exDocType, exStorageKey, exCredentialPrivKey, exSha256Pop] =
+ extractFromTestCredentialData(credentialData);
+
+ ASSERT_TRUE(exSuccess);
+ ASSERT_EQ(exDocType, "org.iso.18013-5.2019.mdl");
+ // ... check that the public key derived from the private key matches what was
+ // in the certificate.
+ optional<vector<uint8_t>> exCredentialKeyPair =
+ support::ecPrivateKeyToKeyPair(exCredentialPrivKey);
+ ASSERT_TRUE(exCredentialKeyPair);
+ optional<vector<uint8_t>> exCredentialPubKey =
+ support::ecKeyPairGetPublicKey(exCredentialKeyPair.value());
+ ASSERT_TRUE(exCredentialPubKey);
+ ASSERT_EQ(exCredentialPubKey.value(), credentialPubKey.value());
+
+ sp<IIdentityCredential> credential;
+ ASSERT_TRUE(credentialStore_
+ ->getCredential(
+ CipherSuite::CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256,
+ credentialData, &credential)
+ .isOk());
+ ASSERT_NE(credential, nullptr);
+
+ // Calculate sessionTranscript, make something that resembles what you'd use for
+ // an over-the-Internet presentation not using mdoc session encryption.
+ cppbor::Array sessionTranscript =
+ cppbor::Array()
+ .add(cppbor::Null()) // DeviceEngagementBytes isn't used.
+ .add(cppbor::Null()) // EReaderKeyBytes isn't used.
+ .add(cppbor::Array() // Proprietary handover structure follows.
+ .add(cppbor::Tstr("TestHandover"))
+ .add(cppbor::Bstr(vector<uint8_t>{1, 2, 3}))
+ .add(cppbor::Bstr(vector<uint8_t>{9, 8, 7, 6})));
+ vector<uint8_t> sessionTranscriptEncoded = sessionTranscript.encode();
+
+ // Generate the key that will be used to sign AuthenticatedData.
+ vector<uint8_t> signingKeyBlob;
+ Certificate signingKeyCertificate;
+ ASSERT_TRUE(credential->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate).isOk());
+ optional<vector<uint8_t>> signingPubKey =
+ support::certificateChainGetTopMostKey(signingKeyCertificate.encodedCertificate);
+ EXPECT_TRUE(signingPubKey);
+ test_utils::verifyAuthKeyCertificate(signingKeyCertificate.encodedCertificate);
+
+ vector<RequestNamespace> requestedNamespaces = test_utils::buildRequestNamespaces(testEntries);
+ ASSERT_TRUE(credential->setRequestedNamespaces(requestedNamespaces).isOk());
+ ASSERT_TRUE(credential->setVerificationToken(verificationToken).isOk());
+ Status status = credential->startRetrieval(
+ secureProfiles.value(), authToken, {} /* itemsRequestBytes*/, signingKeyBlob,
+ sessionTranscriptEncoded, {} /* readerSignature */, testEntriesEntryCounts);
+ ASSERT_TRUE(status.isOk()) << status.exceptionCode() << ": " << status.exceptionMessage();
+
+ for (const auto& entry : testEntries) {
+ ASSERT_TRUE(credential
+ ->startRetrieveEntryValue(entry.nameSpace, entry.name,
+ entry.valueCbor.size(), entry.profileIds)
+ .isOk());
+
+ auto it = encryptedBlobs.find(&entry);
+ ASSERT_NE(it, encryptedBlobs.end());
+ const vector<vector<uint8_t>>& encryptedChunks = it->second;
+
+ vector<uint8_t> content;
+ for (const auto& encryptedChunk : encryptedChunks) {
+ vector<uint8_t> chunk;
+ ASSERT_TRUE(credential->retrieveEntryValue(encryptedChunk, &chunk).isOk());
+ content.insert(content.end(), chunk.begin(), chunk.end());
+ }
+ EXPECT_EQ(content, entry.valueCbor);
+ }
+
+ vector<uint8_t> mac;
+ vector<uint8_t> ecdsaSignature;
+ vector<uint8_t> deviceNameSpacesEncoded;
+ status = credential->finishRetrievalWithSignature(&mac, &deviceNameSpacesEncoded,
+ &ecdsaSignature);
+ ASSERT_TRUE(status.isOk()) << status.exceptionCode() << ": " << status.exceptionMessage();
+ // MACing should NOT work since we're not using session encryption
+ ASSERT_EQ(0, mac.size());
+
+ // ECDSA signatures should work, however. Check this.
+ ASSERT_GT(ecdsaSignature.size(), 0);
+
+ cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
+ ASSERT_EQ(
+ "{\n"
+ " 'PersonalData' : {\n"
+ " 'Last name' : 'Turing',\n"
+ " 'Birth date' : '19120623',\n"
+ " 'First name' : 'Alan',\n"
+ " },\n"
+ "}",
+ cborPretty);
+
+ string docType = "org.iso.18013-5.2019.mdl";
+
+ vector<uint8_t> encodedDeviceAuthentication =
+ cppbor::Array()
+ .add("DeviceAuthentication")
+ .add(sessionTranscript.clone())
+ .add(docType)
+ .add(cppbor::SemanticTag(24, deviceNameSpacesEncoded))
+ .encode();
+ vector<uint8_t> deviceAuthenticationBytes =
+ cppbor::SemanticTag(24, encodedDeviceAuthentication).encode();
+ EXPECT_TRUE(support::coseCheckEcDsaSignature(ecdsaSignature,
+ deviceAuthenticationBytes, // Detached content
+ signingPubKey.value()));
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EndToEndTests);
diff --git a/radio/aidl/Android.bp b/radio/aidl/Android.bp
index 9dbe09a..930b6d4 100644
--- a/radio/aidl/Android.bp
+++ b/radio/aidl/Android.bp
@@ -12,6 +12,7 @@
vendor_available: true,
host_supported: true,
srcs: ["android/hardware/radio/*.aidl"],
+ frozen: false,
stability: "vintf",
backend: {
cpp: {
@@ -35,6 +36,7 @@
vendor_available: true,
host_supported: true,
srcs: ["android/hardware/radio/config/*.aidl"],
+ frozen: false,
stability: "vintf",
imports: ["android.hardware.radio-V2"],
backend: {
diff --git a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensors.aidl b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensors.aidl
index f60f5bb..b26040b 100644
--- a/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensors.aidl
+++ b/sensors/aidl/aidl_api/android.hardware.sensors/current/android/hardware/sensors/ISensors.aidl
@@ -58,6 +58,8 @@
const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_DATA = 24;
const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_RESERVED = 88;
const int DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH = 104;
+ const int RUNTIME_SENSORS_HANDLE_BASE = 1593835520;
+ const int RUNTIME_SENSORS_HANDLE_END = 1610612735;
@Backing(type="int") @VintfStability
enum RateLevel {
STOP = 0,
diff --git a/sensors/aidl/android/hardware/sensors/ISensors.aidl b/sensors/aidl/android/hardware/sensors/ISensors.aidl
index 2c68489..5e276dd 100644
--- a/sensors/aidl/android/hardware/sensors/ISensors.aidl
+++ b/sensors/aidl/android/hardware/sensors/ISensors.aidl
@@ -371,4 +371,13 @@
const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_DATA = 0x18;
const int DIRECT_REPORT_SENSOR_EVENT_OFFSET_SIZE_RESERVED = 0x58;
const int DIRECT_REPORT_SENSOR_EVENT_TOTAL_LENGTH = 104;
+
+ /**
+ * Constants related to reserved sensor handle ranges.
+ *
+ * The following range (inclusive) is reserved for usage by the system for
+ * runtime sensors.
+ */
+ const int RUNTIME_SENSORS_HANDLE_BASE = 0x5F000000;
+ const int RUNTIME_SENSORS_HANDLE_END = 0x5FFFFFFF;
}
diff --git a/sensors/aidl/convert/Android.bp b/sensors/aidl/convert/Android.bp
index 0b31597..53060b9 100644
--- a/sensors/aidl/convert/Android.bp
+++ b/sensors/aidl/convert/Android.bp
@@ -35,7 +35,7 @@
"libhardware",
"libbase",
"libutils",
- "android.hardware.sensors-V1-ndk",
+ "android.hardware.sensors-V2-ndk",
],
whole_static_libs: [
"sensors_common_convert",
diff --git a/sensors/aidl/default/Android.bp b/sensors/aidl/default/Android.bp
index 3c66744..16b4d35 100644
--- a/sensors/aidl/default/Android.bp
+++ b/sensors/aidl/default/Android.bp
@@ -41,7 +41,7 @@
"libfmq",
"libpower",
"libbinder_ndk",
- "android.hardware.sensors-V1-ndk",
+ "android.hardware.sensors-V2-ndk",
],
export_include_dirs: ["include"],
srcs: [
@@ -68,7 +68,7 @@
"libcutils",
"liblog",
"libutils",
- "android.hardware.sensors-V1-ndk",
+ "android.hardware.sensors-V2-ndk",
],
static_libs: [
"libsensorsexampleimpl",
diff --git a/sensors/aidl/default/multihal/Android.bp b/sensors/aidl/default/multihal/Android.bp
index eee1062..a20d6d7 100644
--- a/sensors/aidl/default/multihal/Android.bp
+++ b/sensors/aidl/default/multihal/Android.bp
@@ -38,7 +38,7 @@
"android.hardware.sensors@1.0",
"android.hardware.sensors@2.0",
"android.hardware.sensors@2.1",
- "android.hardware.sensors-V1-ndk",
+ "android.hardware.sensors-V2-ndk",
],
export_include_dirs: ["include"],
srcs: [
diff --git a/sensors/aidl/default/sensors-default.xml b/sensors/aidl/default/sensors-default.xml
index 7898a6b..36b28ed 100644
--- a/sensors/aidl/default/sensors-default.xml
+++ b/sensors/aidl/default/sensors-default.xml
@@ -1,7 +1,7 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.sensors</name>
- <version>1</version>
+ <version>2</version>
<fqname>ISensors/default</fqname>
</hal>
</manifest>
diff --git a/sensors/aidl/multihal/Android.bp b/sensors/aidl/multihal/Android.bp
index 6d35daf..522d305 100644
--- a/sensors/aidl/multihal/Android.bp
+++ b/sensors/aidl/multihal/Android.bp
@@ -40,7 +40,7 @@
"android.hardware.sensors@2.0-ScopedWakelock",
"android.hardware.sensors@2.0",
"android.hardware.sensors@2.1",
- "android.hardware.sensors-V1-ndk",
+ "android.hardware.sensors-V2-ndk",
"libbase",
"libcutils",
"libfmq",
diff --git a/sensors/aidl/multihal/android.hardware.sensors-multihal.xml b/sensors/aidl/multihal/android.hardware.sensors-multihal.xml
index d78edff..5da4fbd 100644
--- a/sensors/aidl/multihal/android.hardware.sensors-multihal.xml
+++ b/sensors/aidl/multihal/android.hardware.sensors-multihal.xml
@@ -17,7 +17,7 @@
<manifest version="1.0" type="device">
<hal format="aidl">
<name>android.hardware.sensors</name>
- <version>1</version>
+ <version>2</version>
<fqname>ISensors/default</fqname>
</hal>
</manifest>
diff --git a/sensors/aidl/vts/Android.bp b/sensors/aidl/vts/Android.bp
index f3972ec..c17a558 100644
--- a/sensors/aidl/vts/Android.bp
+++ b/sensors/aidl/vts/Android.bp
@@ -41,7 +41,7 @@
"android.hardware.common.fmq-V1-ndk",
],
static_libs: [
- "android.hardware.sensors-V1-ndk",
+ "android.hardware.sensors-V2-ndk",
"VtsHalSensorsTargetTestUtils",
"libaidlcommonsupport",
],
diff --git a/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp b/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
index d536e29..ad58e21 100644
--- a/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
+++ b/sensors/aidl/vts/VtsAidlHalSensorsTargetTest.cpp
@@ -560,10 +560,15 @@
EXPECT_NO_FATAL_FAILURE(assertTypeMatchStringType(info.type, info.typeAsString));
}
- // Test if all sensor has name and vendor
+ // Test if all sensors have name and vendor
EXPECT_FALSE(info.name.empty());
EXPECT_FALSE(info.vendor.empty());
+ // Make sure that the sensor handle is not within the reserved range for runtime
+ // sensors.
+ EXPECT_FALSE(ISensors::RUNTIME_SENSORS_HANDLE_BASE <= info.sensorHandle &&
+ info.sensorHandle <= ISensors::RUNTIME_SENSORS_HANDLE_END);
+
// Make sure that sensors of the same type have a unique name.
std::vector<std::string>& v = sensorTypeNameMap[static_cast<int32_t>(info.type)];
bool isUniqueName = std::find(v.begin(), v.end(), info.name) == v.end();
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
index 647891f..f800e8f 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
@@ -59,6 +59,7 @@
@PropagateAllowBlocking android.hardware.wifi.IWifiStaIface getStaIface(in String ifname);
String[] getStaIfaceNames();
android.hardware.wifi.WifiRadioCombinationMatrix getSupportedRadioCombinationsMatrix();
+ android.hardware.wifi.WifiChipCapabilities getWifiChipCapabilities();
android.hardware.wifi.WifiUsableChannel[] getUsableChannels(in android.hardware.wifi.WifiBand band, in android.hardware.wifi.WifiIfaceMode ifaceModeMask, in android.hardware.wifi.IWifiChip.UsableChannelFilter filterMask);
void registerEventCallback(in android.hardware.wifi.IWifiChipEventCallback callback);
void removeApIface(in String ifname);
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiChipCapabilities.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiChipCapabilities.aidl
new file mode 100644
index 0000000..48dc8e0
--- /dev/null
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/WifiChipCapabilities.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.wifi;
+@VintfStability
+parcelable WifiChipCapabilities {
+ int maxMloLinkCount;
+ int maxConcurrentTdlsSessionCount;
+}
diff --git a/wifi/aidl/android/hardware/wifi/IWifiChip.aidl b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
index fe9a6f3..64692af 100644
--- a/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
+++ b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
@@ -25,6 +25,7 @@
import android.hardware.wifi.IfaceConcurrencyType;
import android.hardware.wifi.IfaceType;
import android.hardware.wifi.WifiBand;
+import android.hardware.wifi.WifiChipCapabilities;
import android.hardware.wifi.WifiDebugHostWakeReasonStats;
import android.hardware.wifi.WifiDebugRingBufferStatus;
import android.hardware.wifi.WifiDebugRingBufferVerboseLevel;
@@ -785,6 +786,18 @@
WifiRadioCombinationMatrix getSupportedRadioCombinationsMatrix();
/**
+ * Get capabilities supported by this chip.
+ *
+ * @return Chip capabilities represented by |WifiChipCapabilities|.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.FAILURE_UNKNOWN|
+ *
+ */
+ WifiChipCapabilities getWifiChipCapabilities();
+
+ /**
* Retrieve a list of usable Wifi channels for the specified band &
* operational modes.
*
diff --git a/wifi/aidl/android/hardware/wifi/WifiChipCapabilities.aidl b/wifi/aidl/android/hardware/wifi/WifiChipCapabilities.aidl
new file mode 100644
index 0000000..f65d49a
--- /dev/null
+++ b/wifi/aidl/android/hardware/wifi/WifiChipCapabilities.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi;
+
+/**
+ * WifiChipCapabilities captures various Wifi chip capability params.
+ */
+@VintfStability
+parcelable WifiChipCapabilities {
+ /**
+ * Maximum number of links used in Multi-Link Operation. The maximum
+ * number of links used for MLO can be different from the number of
+ * radios supported by the chip.
+ *
+ * This is a static configuration of the chip.
+ */
+ int maxMloLinkCount;
+ /**
+ * Maximum number of concurrent TDLS sessions that can be enabled
+ * by framework via ISupplicantStaIface#initiateTdlsSetup().
+ */
+ int maxConcurrentTdlsSessionCount;
+}
diff --git a/wifi/aidl/default/aidl_struct_util.cpp b/wifi/aidl/default/aidl_struct_util.cpp
index 07612b6..ec8b396 100644
--- a/wifi/aidl/default/aidl_struct_util.cpp
+++ b/wifi/aidl/default/aidl_struct_util.cpp
@@ -2768,6 +2768,15 @@
return true;
}
+bool convertLegacyWifiChipCapabilitiesToAidl(
+ const legacy_hal::wifi_chip_capabilities& legacy_chip_capabilities,
+ WifiChipCapabilities& aidl_chip_capabilities) {
+ aidl_chip_capabilities.maxMloLinkCount = legacy_chip_capabilities.max_mlo_link_count;
+ aidl_chip_capabilities.maxConcurrentTdlsSessionCount =
+ legacy_chip_capabilities.max_concurrent_tdls_session_count;
+ return true;
+}
+
} // namespace aidl_struct_util
} // namespace wifi
} // namespace hardware
diff --git a/wifi/aidl/default/aidl_struct_util.h b/wifi/aidl/default/aidl_struct_util.h
index 4ebfc10..d8e1fd4 100644
--- a/wifi/aidl/default/aidl_struct_util.h
+++ b/wifi/aidl/default/aidl_struct_util.h
@@ -171,6 +171,9 @@
StaPeerInfo* aidl_peer_info_stats);
bool convertLegacyWifiRateInfoToAidl(const legacy_hal::wifi_rate& legacy_rate,
WifiRateInfo* aidl_rate);
+bool convertLegacyWifiChipCapabilitiesToAidl(
+ const legacy_hal::wifi_chip_capabilities& legacy_chip_capabilities,
+ WifiChipCapabilities& aidl_chip_capabilities);
} // namespace aidl_struct_util
} // namespace wifi
} // namespace hardware
diff --git a/wifi/aidl/default/wifi_chip.cpp b/wifi/aidl/default/wifi_chip.cpp
index 076f351..4061699 100644
--- a/wifi/aidl/default/wifi_chip.cpp
+++ b/wifi/aidl/default/wifi_chip.cpp
@@ -680,6 +680,11 @@
&WifiChip::getSupportedRadioCombinationsMatrixInternal, _aidl_return);
}
+ndk::ScopedAStatus WifiChip::getWifiChipCapabilities(WifiChipCapabilities* _aidl_return) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::getWifiChipCapabilitiesInternal, _aidl_return);
+}
+
void WifiChip::invalidateAndRemoveAllIfaces() {
invalidateAndClearBridgedApAll();
invalidateAndClearAll(ap_ifaces_);
@@ -1403,6 +1408,26 @@
return {aidl_matrix, ndk::ScopedAStatus::ok()};
}
+std::pair<WifiChipCapabilities, ndk::ScopedAStatus> WifiChip::getWifiChipCapabilitiesInternal() {
+ legacy_hal::wifi_error legacy_status;
+ legacy_hal::wifi_chip_capabilities legacy_chip_capabilities;
+ std::tie(legacy_status, legacy_chip_capabilities) =
+ legacy_hal_.lock()->getWifiChipCapabilities();
+ if (legacy_status != legacy_hal::WIFI_SUCCESS) {
+ LOG(ERROR) << "Failed to get chip capabilities from legacy HAL: "
+ << legacyErrorToString(legacy_status);
+ return {WifiChipCapabilities(), createWifiStatusFromLegacyError(legacy_status)};
+ }
+ WifiChipCapabilities aidl_chip_capabilities;
+ if (!aidl_struct_util::convertLegacyWifiChipCapabilitiesToAidl(legacy_chip_capabilities,
+ aidl_chip_capabilities)) {
+ LOG(ERROR) << "Failed convertLegacyWifiChipCapabilitiesToAidl() ";
+ return {WifiChipCapabilities(), createWifiStatus(WifiStatusCode::ERROR_INVALID_ARGS)};
+ }
+
+ return {aidl_chip_capabilities, ndk::ScopedAStatus::ok()};
+}
+
ndk::ScopedAStatus WifiChip::triggerSubsystemRestartInternal() {
auto legacy_status = legacy_hal_.lock()->triggerSubsystemRestart();
return createWifiStatusFromLegacyError(legacy_status);
diff --git a/wifi/aidl/default/wifi_chip.h b/wifi/aidl/default/wifi_chip.h
index 59eaa4a..7b04e85 100644
--- a/wifi/aidl/default/wifi_chip.h
+++ b/wifi/aidl/default/wifi_chip.h
@@ -144,6 +144,7 @@
ndk::ScopedAStatus triggerSubsystemRestart() override;
ndk::ScopedAStatus getSupportedRadioCombinationsMatrix(
WifiRadioCombinationMatrix* _aidl_return) override;
+ ndk::ScopedAStatus getWifiChipCapabilities(WifiChipCapabilities* _aidl_return) override;
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
private:
@@ -250,6 +251,7 @@
ndk::ScopedAStatus triggerSubsystemRestartInternal();
std::pair<WifiRadioCombinationMatrix, ndk::ScopedAStatus>
getSupportedRadioCombinationsMatrixInternal();
+ std::pair<WifiChipCapabilities, ndk::ScopedAStatus> getWifiChipCapabilitiesInternal();
void setWeakPtr(std::weak_ptr<WifiChip> ptr);
int32_t chip_id_;
diff --git a/wifi/aidl/default/wifi_legacy_hal.cpp b/wifi/aidl/default/wifi_legacy_hal.cpp
index 43e73ca..e4883d1 100644
--- a/wifi/aidl/default/wifi_legacy_hal.cpp
+++ b/wifi/aidl/default/wifi_legacy_hal.cpp
@@ -1609,6 +1609,13 @@
return status;
}
+std::pair<wifi_error, wifi_chip_capabilities> WifiLegacyHal::getWifiChipCapabilities() {
+ wifi_chip_capabilities chip_capabilities;
+ wifi_error status =
+ global_func_table_.wifi_get_chip_capabilities(global_handle_, &chip_capabilities);
+ return {status, chip_capabilities};
+}
+
void WifiLegacyHal::invalidate() {
global_handle_ = nullptr;
iface_name_to_handle_.clear();
diff --git a/wifi/aidl/default/wifi_legacy_hal.h b/wifi/aidl/default/wifi_legacy_hal.h
index cd8c0b1..33ed359 100644
--- a/wifi/aidl/default/wifi_legacy_hal.h
+++ b/wifi/aidl/default/wifi_legacy_hal.h
@@ -232,6 +232,7 @@
using ::wifi_channel_info;
using ::wifi_channel_stat;
using ::wifi_channel_width;
+using ::wifi_chip_capabilities;
using ::wifi_coex_restriction;
using ::wifi_coex_unsafe_channel;
using ::WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED;
@@ -693,6 +694,7 @@
wifi_error enableWifiTxPowerLimits(const std::string& iface_name, bool enable);
wifi_error getWifiCachedScanResults(const std::string& iface_name,
const CachedScanResultsCallbackHandlers& handler);
+ std::pair<wifi_error, wifi_chip_capabilities> getWifiChipCapabilities();
private:
// Retrieve interface handles for all the available interfaces.
diff --git a/wifi/aidl/default/wifi_legacy_hal_stubs.cpp b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
index cff7f69..7777894 100644
--- a/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
@@ -167,6 +167,7 @@
populateStubFor(&hal_fn->wifi_chre_register_handler);
populateStubFor(&hal_fn->wifi_enable_tx_power_limits);
populateStubFor(&hal_fn->wifi_get_cached_scan_results);
+ populateStubFor(&hal_fn->wifi_get_chip_capabilities);
return true;
}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
index 6276a35..f9a078b 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
@@ -39,4 +39,5 @@
oneway void onNetworkEapSimUmtsAuthRequest(in android.hardware.wifi.supplicant.NetworkRequestEapSimUmtsAuthParams params);
oneway void onTransitionDisable(in android.hardware.wifi.supplicant.TransitionDisableIndication ind);
oneway void onServerCertificateAvailable(in int depth, in byte[] subject, in byte[] certHash, in byte[] certBlob);
+ oneway void onPermanentIdReqDenied();
}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
index de7b675..4f892be 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicantStaNetworkCallback.aidl
@@ -71,4 +71,11 @@
*/
void onServerCertificateAvailable(
in int depth, in byte[] subject, in byte[] certHash, in byte[] certBlob);
+
+ /**
+ * Used to notify the AT_PERMANENT_ID_REQ denied event.
+ *
+ * In strict conservative mode, AT_PERMANENT_ID_REQ is denied from eap_peer side.
+ */
+ void onPermanentIdReqDenied();
}
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
index 6ff64a5..0aebe6d 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
@@ -100,6 +100,7 @@
const std::vector<uint8_t>& /* certBlob */) override {
return ndk::ScopedAStatus::ok();
}
+ ::ndk::ScopedAStatus onPermanentIdReqDenied() override { return ndk::ScopedAStatus::ok(); }
};
class SupplicantStaNetworkAidlTest