Merge "uwb: Allow Java backened jar to be created"
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Equalizer.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Equalizer.aidl
index d825eac..ea63de5 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Equalizer.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Equalizer.aidl
@@ -37,6 +37,7 @@
android.hardware.audio.effect.VendorExtension vendorExtension;
android.hardware.audio.effect.Equalizer.BandLevel[] bandLevels;
int preset;
+ int[] centerFreqMh;
@VintfStability
union Id {
int vendorExtensionTag;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
index 20f7e02..35186c3 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
@@ -48,9 +48,9 @@
}
@Backing(type="int") @VintfStability
enum VibratorScale {
- MUTE = (-100),
- VERY_LOW = (-2),
- LOW = (-1),
+ MUTE = (-100) /* -100 */,
+ VERY_LOW = (-2) /* -2 */,
+ LOW = (-1) /* -1 */,
NONE = 0,
HIGH = 1,
VERY_HIGH = 2,
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/NoiseSuppression.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/NoiseSuppression.aidl
index 1cf92ef..153e021 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/NoiseSuppression.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/NoiseSuppression.aidl
@@ -36,6 +36,7 @@
union NoiseSuppression {
android.hardware.audio.effect.VendorExtension vendor;
android.hardware.audio.effect.NoiseSuppression.Level level;
+ android.hardware.audio.effect.NoiseSuppression.Type type;
@VintfStability
union Id {
int vendorExtensionTag;
@@ -52,4 +53,9 @@
HIGH,
VERY_HIGH,
}
+ @Backing(type="int") @VintfStability
+ enum Type {
+ SINGLE_CHANNEL,
+ MULTI_CHANNEL,
+ }
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl
index 9fdd692..2f367d9 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl
@@ -36,10 +36,18 @@
union Virtualizer {
android.hardware.audio.effect.VendorExtension vendor;
int strengthPm;
+ android.hardware.audio.effect.Virtualizer.ChannelAngle[] speakerAngles;
+ android.media.audio.common.AudioDeviceDescription device;
@VintfStability
union Id {
int vendorExtensionTag;
android.hardware.audio.effect.Virtualizer.Tag commonTag;
+ android.hardware.audio.effect.Virtualizer.SpeakerAnglesPayload speakerAnglesPayload;
+ }
+ @VintfStability
+ parcelable SpeakerAnglesPayload {
+ android.media.audio.common.AudioChannelLayout layout;
+ android.media.audio.common.AudioDeviceDescription device;
}
@VintfStability
parcelable Capability {
@@ -47,4 +55,10 @@
int maxStrengthPm;
boolean strengthSupported;
}
+ @VintfStability
+ parcelable ChannelAngle {
+ int channel;
+ int azimuthDegree;
+ int elevationDegree;
+ }
}
diff --git a/audio/aidl/android/hardware/audio/effect/Equalizer.aidl b/audio/aidl/android/hardware/audio/effect/Equalizer.aidl
index 79a1c4f..7903fde 100644
--- a/audio/aidl/android/hardware/audio/effect/Equalizer.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Equalizer.aidl
@@ -72,7 +72,7 @@
}
/**
- * Supported minimal and maximal frequency for each band in millihertz.
+ * Supported minimal and maximal frequency for each band in milliHertz.
*/
@VintfStability
parcelable BandFrequency {
@@ -97,8 +97,14 @@
* Level for each band.
*/
BandLevel[] bandLevels;
+
/**
* Index of current preset.
*/
int preset;
+
+ /**
+ * Get only parameter, get the center frequency for all bands in milliHertz.
+ */
+ int[] centerFreqMh;
}
diff --git a/audio/aidl/android/hardware/audio/effect/NoiseSuppression.aidl b/audio/aidl/android/hardware/audio/effect/NoiseSuppression.aidl
index 9969a0b..c4baff8 100644
--- a/audio/aidl/android/hardware/audio/effect/NoiseSuppression.aidl
+++ b/audio/aidl/android/hardware/audio/effect/NoiseSuppression.aidl
@@ -68,4 +68,11 @@
* The NS level.
*/
Level level;
+
+ /**
+ * Noise suppression type.
+ */
+ @VintfStability @Backing(type="int") enum Type { SINGLE_CHANNEL, MULTI_CHANNEL }
+
+ Type type;
}
diff --git a/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl b/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl
index 5f385a6..fc453ad 100644
--- a/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl
@@ -17,6 +17,8 @@
package android.hardware.audio.effect;
import android.hardware.audio.effect.VendorExtension;
+import android.media.audio.common.AudioChannelLayout;
+import android.media.audio.common.AudioDeviceDescription;
/**
* Virtualizer specific definitions. An audio virtualizer is a general name for an effect to
@@ -35,6 +37,7 @@
union Id {
int vendorExtensionTag;
Virtualizer.Tag commonTag;
+ SpeakerAnglesPayload speakerAnglesPayload;
}
/**
@@ -43,6 +46,25 @@
VendorExtension vendor;
/**
+ * Payload to query speaker angles for the given channel position mask and device.
+ * The Virtualizer implementation must return EX_ILLEGAL_ARGUMENT if the given payload not
+ * supported.
+ */
+ @VintfStability
+ parcelable SpeakerAnglesPayload {
+ /**
+ * Audio channel position definition. See
+ * android.media.audio.common.AudioChannelLayout.aidl. Only the channel position "CHANNEL_*"
+ * in AudioChannelLayout be used.
+ */
+ AudioChannelLayout layout;
+ /**
+ * Audio device type. See android.media.audio.common.AudioDeviceDescription.aidl.
+ */
+ AudioDeviceDescription device;
+ }
+
+ /**
* Capability supported by Virtualizer implementation.
*/
@VintfStability
@@ -74,4 +96,39 @@
* the 'maxStrengthPm' capability.
*/
int strengthPm;
+
+ /**
+ * All angles are expressed in degrees and are relative to the listener.
+ */
+ @VintfStability
+ parcelable ChannelAngle {
+ /**
+ * Audio channel layout, CHANNEL_* constants defined in
+ * android.media.audio.common.AudioChannelLayout.
+ */
+ int channel;
+
+ /**
+ * 0 is the direction the listener faces, 180 is behind the listener, and -90 is left of
+ * the listener.
+ */
+ int azimuthDegree;
+
+ /**
+ * 0 is the horizontal plane, +90 is above the listener, -90 is below.
+ */
+ int elevationDegree;
+ }
+
+ /**
+ * Get only parameter.
+ * A vector of angles per channel represented by azimuth and elevation (in degrees), client must
+ * set Parameter.Id to SpeakerAnglesPayload to get speakerAngles.
+ */
+ ChannelAngle[] speakerAngles;
+
+ /**
+ * The audio device on which virtualzation mode is forced.
+ */
+ AudioDeviceDescription device;
}
diff --git a/audio/aidl/common/include/Utils.h b/audio/aidl/common/include/Utils.h
index 2aaa781..d87bbd4 100644
--- a/audio/aidl/common/include/Utils.h
+++ b/audio/aidl/common/include/Utils.h
@@ -104,6 +104,30 @@
device == ::aidl::android::media::audio::common::AudioDeviceType::OUT_TELEPHONY_TX;
}
+constexpr bool isUsbInputDeviceType(::aidl::android::media::audio::common::AudioDeviceType type) {
+ switch (type) {
+ case ::aidl::android::media::audio::common::AudioDeviceType::IN_DOCK:
+ case ::aidl::android::media::audio::common::AudioDeviceType::IN_ACCESSORY:
+ case ::aidl::android::media::audio::common::AudioDeviceType::IN_DEVICE:
+ case ::aidl::android::media::audio::common::AudioDeviceType::IN_HEADSET:
+ return true;
+ default:
+ return false;
+ }
+}
+
+constexpr bool isUsbOutputtDeviceType(::aidl::android::media::audio::common::AudioDeviceType type) {
+ switch (type) {
+ case ::aidl::android::media::audio::common::AudioDeviceType::OUT_DOCK:
+ case ::aidl::android::media::audio::common::AudioDeviceType::OUT_ACCESSORY:
+ case ::aidl::android::media::audio::common::AudioDeviceType::OUT_DEVICE:
+ case ::aidl::android::media::audio::common::AudioDeviceType::OUT_HEADSET:
+ return true;
+ default:
+ return false;
+ }
+}
+
constexpr bool isValidAudioMode(::aidl::android::media::audio::common::AudioMode mode) {
return std::find(kValidAudioModes.begin(), kValidAudioModes.end(), mode) !=
kValidAudioModes.end();
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 856f83f..21616be 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -11,12 +11,14 @@
name: "aidlaudioservice_defaults",
vendor: true,
shared_libs: [
+ "libalsautilsv2",
"libaudioaidlcommon",
"libbase",
"libbinder_ndk",
"libcutils",
"libfmq",
"libstagefright_foundation",
+ "libtinyalsav2",
"libutils",
"libxml2",
"android.hardware.common-V2-ndk",
@@ -71,6 +73,9 @@
"Stream.cpp",
"StreamStub.cpp",
"Telephony.cpp",
+ "usb/ModuleUsb.cpp",
+ "usb/StreamUsb.cpp",
+ "usb/UsbAlsaUtils.cpp",
],
generated_sources: [
"audio_policy_configuration_aidl_default",
diff --git a/audio/aidl/default/EffectThread.cpp b/audio/aidl/default/EffectThread.cpp
index 2b3513d..f7894c4 100644
--- a/audio/aidl/default/EffectThread.cpp
+++ b/audio/aidl/default/EffectThread.cpp
@@ -70,26 +70,14 @@
}
RetCode EffectThread::startThread() {
- if (!mThread.joinable()) {
- LOG(ERROR) << __func__ << " thread already destroyed";
- return RetCode::ERROR_THREAD;
- }
-
- {
- std::lock_guard lg(mThreadMutex);
- if (!mStop) {
- LOG(WARNING) << __func__ << " already start";
- return RetCode::SUCCESS;
- }
- mStop = false;
- }
-
- mCv.notify_one();
- LOG(DEBUG) << __func__ << " done";
- return RetCode::SUCCESS;
+ return handleStartStop(false /* stop */);
}
RetCode EffectThread::stopThread() {
+ return handleStartStop(true /* stop */);
+}
+
+RetCode EffectThread::handleStartStop(bool stop) {
if (!mThread.joinable()) {
LOG(ERROR) << __func__ << " thread already destroyed";
return RetCode::ERROR_THREAD;
@@ -97,13 +85,15 @@
{
std::lock_guard lg(mThreadMutex);
- if (mStop) {
- LOG(WARNING) << __func__ << " already stop";
+ if (stop == mStop) {
+ LOG(WARNING) << __func__ << " already " << stop ? "stop" : "start";
return RetCode::SUCCESS;
}
- mStop = true;
+ mStop = stop;
}
- LOG(DEBUG) << __func__ << " done";
+
+ mCv.notify_one();
+ LOG(DEBUG) << stop ? "stop done" : "start done";
return RetCode::SUCCESS;
}
@@ -111,34 +101,23 @@
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(mThreadMutex);
- mCv.wait(l, [&]() REQUIRES(mThreadMutex) {
- needExit = mExit;
- return mExit || !mStop;
- });
- }
- if (needExit) {
+ std::unique_lock l(mThreadMutex);
+ ::android::base::ScopedLockAssertion lock_assertion(mThreadMutex);
+ mCv.wait(l, [&]() REQUIRES(mThreadMutex) { return mExit || !mStop; });
+ if (mExit) {
LOG(WARNING) << __func__ << " EXIT!";
return;
}
-
- process();
+ process_l();
}
}
-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();
+void EffectThread::process_l() {
+ RETURN_VALUE_IF(!mThreadContext, void(), "nullContext");
+ std::shared_ptr<EffectContext::StatusMQ> statusMQ = mThreadContext->getStatusFmq();
+ std::shared_ptr<EffectContext::DataMQ> inputMQ = mThreadContext->getInputDataFmq();
+ std::shared_ptr<EffectContext::DataMQ> outputMQ = mThreadContext->getOutputDataFmq();
+ auto buffer = mThreadContext->getWorkBuffer();
// Only this worker will read from input data MQ and write to output data MQ.
auto readSamples = inputMQ->availableToRead(), writeSamples = outputMQ->availableToWrite();
@@ -149,7 +128,6 @@
inputMQ->read(buffer, processSamples);
- // call effectProcessImpl without lock
IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples);
outputMQ->write(buffer, status.fmqProduced);
statusMQ->writeBlocking(&status, 1);
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 905ff2c..2f6ab2f 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -27,8 +27,10 @@
#include "core-impl/Bluetooth.h"
#include "core-impl/Module.h"
+#include "core-impl/ModuleUsb.h"
#include "core-impl/SoundDose.h"
#include "core-impl/StreamStub.h"
+#include "core-impl/StreamUsb.h"
#include "core-impl/Telephony.h"
#include "core-impl/utils.h"
@@ -104,6 +106,42 @@
} // namespace
+// static
+std::shared_ptr<Module> Module::createInstance(Type type) {
+ switch (type) {
+ case Module::Type::USB:
+ return ndk::SharedRefBase::make<ModuleUsb>(type);
+ case Type::DEFAULT:
+ case Type::R_SUBMIX:
+ default:
+ return ndk::SharedRefBase::make<Module>(type);
+ }
+}
+
+// static
+StreamIn::CreateInstance Module::getStreamInCreator(Type type) {
+ switch (type) {
+ case Type::USB:
+ return StreamInUsb::createInstance;
+ case Type::DEFAULT:
+ case Type::R_SUBMIX:
+ default:
+ return StreamInStub::createInstance;
+ }
+}
+
+// static
+StreamOut::CreateInstance Module::getStreamOutCreator(Type type) {
+ switch (type) {
+ case Type::USB:
+ return StreamOutUsb::createInstance;
+ case Type::DEFAULT:
+ case Type::R_SUBMIX:
+ default:
+ return StreamOutStub::createInstance;
+ }
+}
+
void Module::cleanUpPatch(int32_t patchId) {
erase_all_values(mPatches, std::set<int32_t>{patchId});
}
@@ -153,6 +191,7 @@
std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
portConfigIt->format.value(), portConfigIt->channelMask.value(),
+ portConfigIt->sampleRate.value().value,
std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
asyncCallback, outEventCallback, params);
if (temp.isValid()) {
@@ -261,6 +300,7 @@
break;
case Type::USB:
mConfig = std::move(internal::getUsbConfiguration());
+ break;
}
}
return *mConfig;
@@ -401,6 +441,8 @@
if (!mDebug.simulateDeviceConnections) {
// In a real HAL here we would attempt querying the profiles from the device.
LOG(ERROR) << __func__ << ": failed to query supported device profiles";
+ // TODO: Check the return value when it is ready for actual devices.
+ populateConnectedDevicePort(&connectedPort);
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
@@ -560,10 +602,9 @@
}
context.fillDescriptor(&_aidl_return->desc);
std::shared_ptr<StreamIn> stream;
- // TODO: Add a mapping from module instance names to a corresponding 'createInstance'.
- if (auto status = StreamInStub::createInstance(in_args.sinkMetadata, std::move(context),
- mConfig->microphones, &stream);
- !status.isOk()) {
+ ndk::ScopedAStatus status = getStreamInCreator(mType)(in_args.sinkMetadata, std::move(context),
+ mConfig->microphones, &stream);
+ if (!status.isOk()) {
return status;
}
StreamWrapper streamWrapper(stream);
@@ -615,10 +656,9 @@
}
context.fillDescriptor(&_aidl_return->desc);
std::shared_ptr<StreamOut> stream;
- // TODO: Add a mapping from module instance names to a corresponding 'createInstance'.
- if (auto status = StreamOutStub::createInstance(in_args.sourceMetadata, std::move(context),
- in_args.offloadInfo, &stream);
- !status.isOk()) {
+ ndk::ScopedAStatus status = getStreamOutCreator(mType)(
+ in_args.sourceMetadata, std::move(context), in_args.offloadInfo, &stream);
+ if (!status.isOk()) {
return status;
}
StreamWrapper streamWrapper(stream);
@@ -696,6 +736,10 @@
}
}
+ if (auto status = checkAudioPatchEndpointsMatch(sources, sinks); !status.isOk()) {
+ return status;
+ }
+
auto& patches = getConfig().patches;
auto existing = patches.end();
std::optional<decltype(mPatches)> patchesBackup;
@@ -1190,4 +1234,16 @@
return mIsMmapSupported.value();
}
+ndk::ScopedAStatus Module::populateConnectedDevicePort(AudioPort* audioPort __unused) {
+ LOG(DEBUG) << __func__ << ": do nothing and return ok";
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Module::checkAudioPatchEndpointsMatch(
+ const std::vector<AudioPortConfig*>& sources __unused,
+ const std::vector<AudioPortConfig*>& sinks __unused) {
+ LOG(DEBUG) << __func__ << ": do nothing and return ok";
+ return ndk::ScopedAStatus::ok();
+}
+
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index 25814e4..d62ca1d 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -135,10 +135,16 @@
mState = StreamDescriptor::State::ERROR;
return Status::ABORT;
}
- LOG(DEBUG) << __func__ << ": received command " << command.toString() << " in " << kThreadName;
+ using Tag = StreamDescriptor::Command::Tag;
+ using LogSeverity = ::android::base::LogSeverity;
+ const LogSeverity severity =
+ command.getTag() == Tag::burst || command.getTag() == Tag::getStatus
+ ? LogSeverity::VERBOSE
+ : LogSeverity::DEBUG;
+ LOG(severity) << __func__ << ": received command " << command.toString() << " in "
+ << kThreadName;
StreamDescriptor::Reply reply{};
reply.status = STATUS_BAD_VALUE;
- using Tag = StreamDescriptor::Command::Tag;
switch (command.getTag()) {
case Tag::halReservedExit:
if (const int32_t cookie = command.get<Tag::halReservedExit>();
@@ -166,8 +172,8 @@
break;
case Tag::burst:
if (const int32_t fmqByteCount = command.get<Tag::burst>(); fmqByteCount >= 0) {
- LOG(DEBUG) << __func__ << ": '" << toString(command.getTag()) << "' command for "
- << fmqByteCount << " bytes";
+ LOG(VERBOSE) << __func__ << ": '" << toString(command.getTag()) << "' command for "
+ << fmqByteCount << " bytes";
if (mState == StreamDescriptor::State::IDLE ||
mState == StreamDescriptor::State::ACTIVE ||
mState == StreamDescriptor::State::PAUSED ||
@@ -253,7 +259,7 @@
break;
}
reply.state = mState;
- LOG(DEBUG) << __func__ << ": writing reply " << reply.toString();
+ LOG(severity) << __func__ << ": writing reply " << reply.toString();
if (!mReplyMQ->writeBlocking(&reply, 1)) {
LOG(ERROR) << __func__ << ": writing of reply " << reply.toString() << " to MQ failed";
mState = StreamDescriptor::State::ERROR;
@@ -284,8 +290,8 @@
if (bool success =
actualByteCount > 0 ? mDataMQ->write(&mDataBuffer[0], actualByteCount) : true;
success) {
- LOG(DEBUG) << __func__ << ": writing of " << actualByteCount << " bytes into data MQ"
- << " succeeded; connected? " << isConnected;
+ LOG(VERBOSE) << __func__ << ": writing of " << actualByteCount << " bytes into data MQ"
+ << " succeeded; connected? " << isConnected;
// Frames are provided and counted regardless of connection status.
reply->fmqByteCount += actualByteCount;
mFrameCount += actualFrameCount;
@@ -340,7 +346,14 @@
mState = StreamDescriptor::State::ERROR;
return Status::ABORT;
}
- LOG(DEBUG) << __func__ << ": received command " << command.toString() << " in " << kThreadName;
+ using Tag = StreamDescriptor::Command::Tag;
+ using LogSeverity = ::android::base::LogSeverity;
+ const LogSeverity severity =
+ command.getTag() == Tag::burst || command.getTag() == Tag::getStatus
+ ? LogSeverity::VERBOSE
+ : LogSeverity::DEBUG;
+ LOG(severity) << __func__ << ": received command " << command.toString() << " in "
+ << kThreadName;
StreamDescriptor::Reply reply{};
reply.status = STATUS_BAD_VALUE;
using Tag = StreamDescriptor::Command::Tag;
@@ -383,8 +396,8 @@
} break;
case Tag::burst:
if (const int32_t fmqByteCount = command.get<Tag::burst>(); fmqByteCount >= 0) {
- LOG(DEBUG) << __func__ << ": '" << toString(command.getTag()) << "' command for "
- << fmqByteCount << " bytes";
+ LOG(VERBOSE) << __func__ << ": '" << toString(command.getTag()) << "' command for "
+ << fmqByteCount << " bytes";
if (mState != StreamDescriptor::State::ERROR &&
mState != StreamDescriptor::State::TRANSFERRING &&
mState != StreamDescriptor::State::TRANSFER_PAUSED) {
@@ -499,7 +512,7 @@
break;
}
reply.state = mState;
- LOG(DEBUG) << __func__ << ": writing reply " << reply.toString();
+ LOG(severity) << __func__ << ": writing reply " << reply.toString();
if (!mReplyMQ->writeBlocking(&reply, 1)) {
LOG(ERROR) << __func__ << ": writing of reply " << reply.toString() << " to MQ failed";
mState = StreamDescriptor::State::ERROR;
@@ -514,8 +527,8 @@
int32_t latency = Module::kLatencyMs;
if (bool success = readByteCount > 0 ? mDataMQ->read(&mDataBuffer[0], readByteCount) : true) {
const bool isConnected = mIsConnected;
- LOG(DEBUG) << __func__ << ": reading of " << readByteCount << " bytes from data MQ"
- << " succeeded; connected? " << isConnected;
+ LOG(VERBOSE) << __func__ << ": reading of " << readByteCount << " bytes from data MQ"
+ << " succeeded; connected? " << isConnected;
// Amount of data that the HAL module is going to actually use.
size_t byteCount = std::min({clientSize, readByteCount, mDataBufferSize});
if (byteCount >= mFrameSize && mForceTransientBurst) {
diff --git a/audio/aidl/default/StreamStub.cpp b/audio/aidl/default/StreamStub.cpp
index 5442179..85d1e16 100644
--- a/audio/aidl/default/StreamStub.cpp
+++ b/audio/aidl/default/StreamStub.cpp
@@ -22,6 +22,7 @@
using aidl::android::hardware::audio::common::SinkMetadata;
using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::media::audio::common::AudioDevice;
using aidl::android::media::audio::common::AudioOffloadInfo;
namespace aidl::android::hardware::audio::core {
@@ -68,6 +69,11 @@
return ::android::OK;
}
+::android::status_t DriverStub::setConnectedDevices(
+ const std::vector<AudioDevice>& connectedDevices __unused) {
+ return ::android::OK;
+}
+
// static
ndk::ScopedAStatus StreamInStub::createInstance(const SinkMetadata& sinkMetadata,
StreamContext&& context,
diff --git a/audio/aidl/default/equalizer/EqualizerSw.cpp b/audio/aidl/default/equalizer/EqualizerSw.cpp
index 984b943..0a6ac34 100644
--- a/audio/aidl/default/equalizer/EqualizerSw.cpp
+++ b/audio/aidl/default/equalizer/EqualizerSw.cpp
@@ -150,6 +150,10 @@
eqParam.set<Equalizer::preset>(mContext->getEqPreset());
break;
}
+ case Equalizer::centerFreqMh: {
+ eqParam.set<Equalizer::centerFreqMh>(mContext->getCenterFreqs());
+ break;
+ }
default: {
LOG(ERROR) << __func__ << " not handled tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
diff --git a/audio/aidl/default/equalizer/EqualizerSw.h b/audio/aidl/default/equalizer/EqualizerSw.h
index 65a8002..fabcfeb 100644
--- a/audio/aidl/default/equalizer/EqualizerSw.h
+++ b/audio/aidl/default/equalizer/EqualizerSw.h
@@ -68,10 +68,16 @@
return bandLevels;
}
+ std::vector<int> getCenterFreqs() {
+ return {std::begin(kPresetsFrequencies), std::end(kPresetsFrequencies)};
+ }
+
private:
static const int NUM_OF_BANDS = 5;
static const int NUM_OF_PRESETS = 10;
static const int PRESET_CUSTOM = -1;
+ static constexpr std::array<uint16_t, NUM_OF_BANDS> kPresetsFrequencies = {60, 230, 910, 3600,
+ 14000};
// preset band level
int mPreset = PRESET_CUSTOM;
int32_t mBandLevels[NUM_OF_BANDS] = {3, 0, 0, 0, 3};
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index 80a22dc..fab1c14 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -35,6 +35,10 @@
explicit Module(Type type) : mType(type) {}
+ static std::shared_ptr<Module> createInstance(Type type);
+ static StreamIn::CreateInstance getStreamInCreator(Type type);
+ static StreamOut::CreateInstance getStreamOutCreator(Type type);
+
private:
struct VendorDebug {
static const std::string kForceTransientBurstName;
@@ -163,6 +167,17 @@
std::shared_ptr<sounddose::ISoundDose> mSoundDose;
ndk::SpAIBinder mSoundDoseBinder;
std::optional<bool> mIsMmapSupported;
+
+ protected:
+ // If the module is unable to populate the connected device port correctly, the returned error
+ // code must correspond to the errors of `IModule.connectedExternalDevice` method.
+ virtual ndk::ScopedAStatus populateConnectedDevicePort(
+ ::aidl::android::media::audio::common::AudioPort* audioPort);
+ // If the module finds that the patch endpoints configurations are not matched, the returned
+ // error code must correspond to the errors of `IModule.setAudioPatch` method.
+ virtual ndk::ScopedAStatus checkAudioPatchEndpointsMatch(
+ const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources,
+ const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks);
};
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/ModuleUsb.h b/audio/aidl/default/include/core-impl/ModuleUsb.h
new file mode 100644
index 0000000..7b177e8
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/ModuleUsb.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "core-impl/Module.h"
+
+namespace aidl::android::hardware::audio::core {
+
+class ModuleUsb : public Module {
+ public:
+ explicit ModuleUsb(Module::Type type) : Module(type) {}
+
+ private:
+ // IModule interfaces
+ ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override;
+ ndk::ScopedAStatus getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) override;
+ ndk::ScopedAStatus getMasterMute(bool* _aidl_return) override;
+ ndk::ScopedAStatus setMasterMute(bool in_mute) override;
+ ndk::ScopedAStatus getMasterVolume(float* _aidl_return) override;
+ ndk::ScopedAStatus setMasterVolume(float in_volume) override;
+ ndk::ScopedAStatus getMicMute(bool* _aidl_return) override;
+ ndk::ScopedAStatus setMicMute(bool in_mute) override;
+
+ // Module interfaces
+ ndk::ScopedAStatus populateConnectedDevicePort(
+ ::aidl::android::media::audio::common::AudioPort* audioPort) override;
+ ndk::ScopedAStatus checkAudioPatchEndpointsMatch(
+ const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sources,
+ const std::vector<::aidl::android::media::audio::common::AudioPortConfig*>& sinks)
+ override;
+};
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 7cd4259..f8c12e6 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -77,7 +77,8 @@
StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ,
const ::aidl::android::media::audio::common::AudioFormatDescription& format,
const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout,
- std::unique_ptr<DataMQ> dataMQ, std::shared_ptr<IStreamCallback> asyncCallback,
+ int sampleRate, std::unique_ptr<DataMQ> dataMQ,
+ std::shared_ptr<IStreamCallback> asyncCallback,
std::shared_ptr<IStreamOutEventCallback> outEventCallback,
DebugParameters debugParameters)
: mCommandMQ(std::move(commandMQ)),
@@ -85,6 +86,7 @@
mReplyMQ(std::move(replyMQ)),
mFormat(format),
mChannelLayout(channelLayout),
+ mSampleRate(sampleRate),
mDataMQ(std::move(dataMQ)),
mAsyncCallback(asyncCallback),
mOutEventCallback(outEventCallback),
@@ -95,6 +97,7 @@
mReplyMQ(std::move(other.mReplyMQ)),
mFormat(other.mFormat),
mChannelLayout(other.mChannelLayout),
+ mSampleRate(other.mSampleRate),
mDataMQ(std::move(other.mDataMQ)),
mAsyncCallback(std::move(other.mAsyncCallback)),
mOutEventCallback(std::move(other.mOutEventCallback)),
@@ -105,6 +108,7 @@
mReplyMQ = std::move(other.mReplyMQ);
mFormat = std::move(other.mFormat);
mChannelLayout = std::move(other.mChannelLayout);
+ mSampleRate = other.mSampleRate;
mDataMQ = std::move(other.mDataMQ);
mAsyncCallback = std::move(other.mAsyncCallback);
mOutEventCallback = std::move(other.mOutEventCallback);
@@ -131,6 +135,7 @@
}
ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
int getTransientStateDelayMs() const { return mDebugParameters.transientStateDelayMs; }
+ int getSampleRate() const { return mSampleRate; }
bool isValid() const;
void reset();
@@ -140,6 +145,7 @@
std::unique_ptr<ReplyMQ> mReplyMQ;
::aidl::android::media::audio::common::AudioFormatDescription mFormat;
::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout;
+ int mSampleRate;
std::unique_ptr<DataMQ> mDataMQ;
std::shared_ptr<IStreamCallback> mAsyncCallback;
std::shared_ptr<IStreamOutEventCallback> mOutEventCallback; // Only used by output streams
@@ -151,6 +157,11 @@
virtual ~DriverInterface() = default;
// This function is called once, on the main thread, before starting the worker thread.
virtual ::android::status_t init() = 0;
+ // This function is called from Binder pool thread. It must be done in a thread-safe manner
+ // if this method and other methods in this interface share data.
+ virtual ::android::status_t setConnectedDevices(
+ const std::vector<::aidl::android::media::audio::common::AudioDevice>&
+ connectedDevices) = 0;
// All the functions below are called on the worker thread.
virtual ::android::status_t drain(StreamDescriptor::DrainMode mode) = 0;
virtual ::android::status_t flush() = 0;
@@ -370,6 +381,7 @@
const std::vector<::aidl::android::media::audio::common::AudioDevice>& devices) {
mWorker->setIsConnected(!devices.empty());
mConnectedDevices = devices;
+ mDriver->setConnectedDevices(devices);
}
ndk::ScopedAStatus updateMetadata(const Metadata& metadata);
diff --git a/audio/aidl/default/include/core-impl/StreamStub.h b/audio/aidl/default/include/core-impl/StreamStub.h
index 98a062a..aea9da5 100644
--- a/audio/aidl/default/include/core-impl/StreamStub.h
+++ b/audio/aidl/default/include/core-impl/StreamStub.h
@@ -24,6 +24,9 @@
public:
DriverStub(const StreamContext& context, bool isInput);
::android::status_t init() override;
+ ::android::status_t setConnectedDevices(
+ const std::vector<::aidl::android::media::audio::common::AudioDevice>& connectedDevices)
+ override;
::android::status_t drain(StreamDescriptor::DrainMode) override;
::android::status_t flush() override;
::android::status_t pause() override;
diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h
new file mode 100644
index 0000000..8ac1f34
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/StreamUsb.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <mutex>
+
+#include <aidl/android/media/audio/common/AudioChannelLayout.h>
+
+#include "core-impl/Stream.h"
+
+extern "C" {
+#include <tinyalsa/pcm.h>
+#include "alsa_device_proxy.h"
+}
+
+namespace aidl::android::hardware::audio::core {
+
+class DriverUsb : public DriverInterface {
+ public:
+ DriverUsb(const StreamContext& context, bool isInput);
+ ::android::status_t init() override;
+ ::android::status_t setConnectedDevices(
+ const std::vector<::aidl::android::media::audio::common::AudioDevice>& connectedDevices)
+ override;
+ ::android::status_t drain(StreamDescriptor::DrainMode) override;
+ ::android::status_t flush() override;
+ ::android::status_t pause() override;
+ ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
+ int32_t* latencyMs) override;
+ ::android::status_t standby() override;
+
+ private:
+ ::android::status_t exitStandby();
+
+ std::mutex mLock;
+
+ const size_t mFrameSizeBytes;
+ std::optional<struct pcm_config> mConfig;
+ const bool mIsInput;
+ // Cached device addresses for connected devices.
+ std::vector<::aidl::android::media::audio::common::AudioDeviceAddress> mConnectedDevices
+ GUARDED_BY(mLock);
+ std::vector<std::shared_ptr<alsa_device_proxy>> mAlsaDeviceProxies GUARDED_BY(mLock);
+ bool mIsStandby = false;
+};
+
+class StreamInUsb final : public StreamIn {
+ ndk::ScopedAStatus getActiveMicrophones(
+ std::vector<MicrophoneDynamicInfo>* _aidl_return) override;
+
+ public:
+ static ndk::ScopedAStatus createInstance(
+ const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
+ StreamContext&& context, const std::vector<MicrophoneInfo>& microphones,
+ std::shared_ptr<StreamIn>* result);
+
+ private:
+ friend class ndk::SharedRefBase;
+ StreamInUsb(const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
+ StreamContext&& context, const std::vector<MicrophoneInfo>& microphones);
+};
+
+class StreamOutUsb final : public StreamOut {
+ public:
+ static ndk::ScopedAStatus createInstance(
+ const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
+ StreamContext&& context,
+ const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
+ offloadInfo,
+ std::shared_ptr<StreamOut>* result);
+
+ private:
+ friend class ndk::SharedRefBase;
+ StreamOutUsb(const ::aidl::android::hardware::audio::common::SourceMetadata& sourceMetadata,
+ StreamContext&& context,
+ const std::optional<::aidl::android::media::audio::common::AudioOffloadInfo>&
+ offloadInfo);
+};
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/utils.h b/audio/aidl/default/include/core-impl/utils.h
index 9d06f08..ae33227 100644
--- a/audio/aidl/default/include/core-impl/utils.h
+++ b/audio/aidl/default/include/core-impl/utils.h
@@ -17,6 +17,7 @@
#pragma once
#include <algorithm>
+#include <map>
#include <set>
#include <vector>
@@ -101,4 +102,21 @@
return result;
}
+// Assuming that M is a map whose keys' type is K and values' type is V,
+// return the corresponding value of the given key from the map or default
+// value if the key is not found.
+template <typename M, typename K, typename V>
+auto findValueOrDefault(const M& m, const K& key, V defaultValue) {
+ auto it = m.find(key);
+ return it == m.end() ? defaultValue : it->second;
+}
+
+// Assuming that M is a map whose keys' type is K, return the given key if it
+// is found from the map or default value.
+template <typename M, typename K>
+auto findKeyOrDefault(const M& m, const K& key, K defaultValue) {
+ auto it = m.find(key);
+ return it == m.end() ? defaultValue : key;
+}
+
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/effect-impl/EffectThread.h b/audio/aidl/default/include/effect-impl/EffectThread.h
index 4b6cecd..9b1a75b 100644
--- a/audio/aidl/default/include/effect-impl/EffectThread.h
+++ b/audio/aidl/default/include/effect-impl/EffectThread.h
@@ -54,6 +54,9 @@
* EffectThread will make sure effectProcessImpl only be called after startThread() successful
* and before stopThread() successful.
*
+ * effectProcessImpl implementation must not call any EffectThread interface, otherwise it will
+ * cause deadlock.
+ *
* @param in address of input float buffer.
* @param out address of output float buffer.
* @param samples number of samples to process.
@@ -62,16 +65,11 @@
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.
+ * process() call effectProcessImpl() for effect data processing, it is necessary for the
+ * processing to be called under Effect thread mutex mThreadMutex, to avoid the effect state
+ * change before/during data processing, and keep the thread and effect state consistent.
*/
- virtual void process();
+ virtual void process_l() REQUIRES(mThreadMutex);
private:
const int kMaxTaskNameLen = 15;
@@ -83,5 +81,7 @@
std::thread mThread;
int mPriority;
std::string mName;
+
+ RetCode handleStartStop(bool stop);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/main.cpp b/audio/aidl/default/main.cpp
index 1933509..a861f9d 100644
--- a/audio/aidl/default/main.cpp
+++ b/audio/aidl/default/main.cpp
@@ -25,9 +25,11 @@
#include "core-impl/Config.h"
#include "core-impl/Module.h"
+#include "core-impl/ModuleUsb.h"
using aidl::android::hardware::audio::core::Config;
using aidl::android::hardware::audio::core::Module;
+using aidl::android::hardware::audio::core::ModuleUsb;
int main() {
// Random values are used in the implementation.
@@ -35,6 +37,8 @@
// This is a debug implementation, always enable debug logging.
android::base::SetMinimumLogSeverity(::android::base::DEBUG);
+ // For more logs, use VERBOSE, however this may hinder performance.
+ // android::base::SetMinimumLogSeverity(::android::base::VERBOSE);
ABinderProcess_setThreadPoolMaxThreadCount(16);
// Make the default config service
@@ -46,7 +50,7 @@
// Make modules
auto createModule = [](Module::Type type, const std::string& instance) {
- auto module = ndk::SharedRefBase::make<Module>(type);
+ auto module = Module::createInstance(type);
ndk::SpAIBinder moduleBinder = module->asBinder();
const std::string moduleName = std::string(Module::descriptor).append("/").append(instance);
AIBinder_setMinSchedulerPolicy(moduleBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
diff --git a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp
index a36cfe0..51fe4ea 100644
--- a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp
+++ b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.cpp
@@ -90,10 +90,15 @@
switch (tag) {
case NoiseSuppression::level: {
RETURN_IF(mContext->setLevel(param.get<NoiseSuppression::level>()) != RetCode::SUCCESS,
- EX_ILLEGAL_ARGUMENT, "levelSupported");
+ EX_ILLEGAL_ARGUMENT, "levelNotSupported");
return ndk::ScopedAStatus::ok();
}
- default: {
+ case NoiseSuppression::type: {
+ RETURN_IF(mContext->setType(param.get<NoiseSuppression::type>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "typeNotSupported");
+ return ndk::ScopedAStatus::ok();
+ }
+ case NoiseSuppression::vendor: {
LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
EX_ILLEGAL_ARGUMENT, "NoiseSuppressionTagNotSupported");
@@ -111,10 +116,11 @@
case NoiseSuppression::Id::commonTag:
return getParameterNoiseSuppression(specificId.get<NoiseSuppression::Id::commonTag>(),
specific);
- default:
+ case NoiseSuppression::Id::vendorExtensionTag: {
LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
EX_ILLEGAL_ARGUMENT, "NoiseSuppressionTagNotSupported");
+ }
}
}
@@ -127,7 +133,11 @@
param.set<NoiseSuppression::level>(mContext->getLevel());
break;
}
- default: {
+ case NoiseSuppression::type: {
+ param.set<NoiseSuppression::type>(mContext->getType());
+ break;
+ }
+ case NoiseSuppression::vendor: {
LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
EX_ILLEGAL_ARGUMENT, "NoiseSuppressionTagNotSupported");
@@ -177,4 +187,9 @@
return mLevel;
}
+RetCode NoiseSuppressionSwContext::setType(NoiseSuppression::Type type) {
+ mType = type;
+ return RetCode::SUCCESS;
+}
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h
index f39d8e5..a851e38 100644
--- a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h
+++ b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h
@@ -35,9 +35,12 @@
RetCode setLevel(NoiseSuppression::Level level);
NoiseSuppression::Level getLevel();
+ RetCode setType(NoiseSuppression::Type type);
+ NoiseSuppression::Type getType() { return mType; }
private:
NoiseSuppression::Level mLevel = NoiseSuppression::Level::LOW;
+ NoiseSuppression::Type mType = NoiseSuppression::Type::SINGLE_CHANNEL;
};
class NoiseSuppressionSw final : public EffectImpl {
diff --git a/audio/aidl/default/usb/ModuleUsb.cpp b/audio/aidl/default/usb/ModuleUsb.cpp
new file mode 100644
index 0000000..e803420
--- /dev/null
+++ b/audio/aidl/default/usb/ModuleUsb.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_ModuleUsb"
+
+#include <vector>
+
+#include <Utils.h>
+#include <android-base/logging.h>
+#include <tinyalsa/asoundlib.h>
+
+#include "UsbAlsaUtils.h"
+#include "core-impl/ModuleUsb.h"
+
+extern "C" {
+#include "alsa_device_profile.h"
+}
+
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioDeviceDescription;
+using aidl::android::media::audio::common::AudioDeviceType;
+using aidl::android::media::audio::common::AudioFormatDescription;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioProfile;
+using android::hardware::audio::common::isUsbInputDeviceType;
+
+namespace aidl::android::hardware::audio::core {
+
+namespace {
+
+std::vector<AudioChannelLayout> populateChannelMasksFromProfile(const alsa_device_profile* profile,
+ bool isInput) {
+ std::vector<AudioChannelLayout> channels;
+ for (size_t i = 0; i < AUDIO_PORT_MAX_CHANNEL_MASKS && profile->channel_counts[i] != 0; ++i) {
+ auto layoutMask =
+ usb::getChannelLayoutMaskFromChannelCount(profile->channel_counts[i], isInput);
+ if (layoutMask.getTag() == AudioChannelLayout::Tag::layoutMask) {
+ channels.push_back(layoutMask);
+ }
+ auto indexMask = usb::getChannelIndexMaskFromChannelCount(profile->channel_counts[i]);
+ if (indexMask.getTag() == AudioChannelLayout::Tag::indexMask) {
+ channels.push_back(indexMask);
+ }
+ }
+ return channels;
+}
+
+std::vector<int> populateSampleRatesFromProfile(const alsa_device_profile* profile) {
+ std::vector<int> sampleRates;
+ for (int i = 0; i < std::min(MAX_PROFILE_SAMPLE_RATES, AUDIO_PORT_MAX_SAMPLING_RATES) &&
+ profile->sample_rates[i] != 0;
+ i++) {
+ sampleRates.push_back(profile->sample_rates[i]);
+ }
+ return sampleRates;
+}
+
+} // namespace
+
+ndk::ScopedAStatus ModuleUsb::getTelephony(std::shared_ptr<ITelephony>* _aidl_return) {
+ *_aidl_return = nullptr;
+ LOG(DEBUG) << __func__ << ": returning null";
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleUsb::getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) {
+ *_aidl_return = nullptr;
+ LOG(DEBUG) << __func__ << ": returning null";
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleUsb::getMasterMute(bool* _aidl_return __unused) {
+ LOG(DEBUG) << __func__ << ": is not supported";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus ModuleUsb::setMasterMute(bool in_mute __unused) {
+ LOG(DEBUG) << __func__ << ": is not supported";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus ModuleUsb::getMasterVolume(float* _aidl_return __unused) {
+ LOG(DEBUG) << __func__ << ": is not supported";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus ModuleUsb::setMasterVolume(float in_volume __unused) {
+ LOG(DEBUG) << __func__ << ": is not supported";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus ModuleUsb::getMicMute(bool* _aidl_return __unused) {
+ LOG(DEBUG) << __func__ << ": is not supported";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus ModuleUsb::setMicMute(bool in_mute __unused) {
+ LOG(DEBUG) << __func__ << ": is not supported";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus ModuleUsb::populateConnectedDevicePort(AudioPort* audioPort) {
+ if (audioPort->ext.getTag() != AudioPortExt::Tag::device) {
+ LOG(ERROR) << __func__ << ": port id " << audioPort->id << " is not a device port";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ auto& devicePort = audioPort->ext.get<AudioPortExt::Tag::device>();
+ if (devicePort.device.type.connection != AudioDeviceDescription::CONNECTION_USB) {
+ LOG(ERROR) << __func__ << ": port id " << audioPort->id << " is not a usb device port";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ if (devicePort.device.address.getTag() != AudioDeviceAddress::Tag::alsa) {
+ LOG(ERROR) << __func__ << ": port id " << audioPort->id << " is not using alsa address";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ auto& alsaAddress = devicePort.device.address.get<AudioDeviceAddress::Tag::alsa>();
+ if (alsaAddress.size() != 2 || alsaAddress[0] < 0 || alsaAddress[1] < 0) {
+ LOG(ERROR) << __func__ << ": port id " << audioPort->id << " invalid alsa address";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+
+ const bool isInput = isUsbInputDeviceType(devicePort.device.type.type);
+ alsa_device_profile profile;
+ profile_init(&profile, isInput ? PCM_IN : PCM_OUT);
+ if (!profile_read_device_info(&profile)) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+
+ std::vector<AudioChannelLayout> channels = populateChannelMasksFromProfile(&profile, isInput);
+ std::vector<int> sampleRates = populateSampleRatesFromProfile(&profile);
+
+ for (size_t i = 0; i < std::min(MAX_PROFILE_FORMATS, AUDIO_PORT_MAX_AUDIO_PROFILES) &&
+ profile.formats[i] != 0;
+ ++i) {
+ auto audioFormatDescription =
+ usb::legacy2aidl_pcm_format_AudioFormatDescription(profile.formats[i]);
+ if (audioFormatDescription.type == AudioFormatType::DEFAULT) {
+ LOG(WARNING) << __func__ << ": unknown pcm type=" << profile.formats[i];
+ continue;
+ }
+ AudioProfile audioProfile = {.format = audioFormatDescription,
+ .channelMasks = channels,
+ .sampleRates = sampleRates};
+ audioPort->profiles.push_back(std::move(audioProfile));
+ }
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleUsb::checkAudioPatchEndpointsMatch(
+ const std::vector<AudioPortConfig*>& sources, const std::vector<AudioPortConfig*>& sinks) {
+ for (const auto& source : sources) {
+ for (const auto& sink : sinks) {
+ if (source->sampleRate != sink->sampleRate ||
+ source->channelMask != sink->channelMask || source->format != sink->format) {
+ LOG(ERROR) << __func__
+ << ": mismatch port configuration, source=" << source->toString()
+ << ", sink=" << sink->toString();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+ }
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp
new file mode 100644
index 0000000..22e36ac
--- /dev/null
+++ b/audio/aidl/default/usb/StreamUsb.cpp
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_StreamUsb"
+#include <android-base/logging.h>
+
+#include "UsbAlsaUtils.h"
+#include "core-impl/Module.h"
+#include "core-impl/StreamUsb.h"
+
+extern "C" {
+#include "alsa_device_profile.h"
+}
+
+using aidl::android::hardware::audio::common::SinkMetadata;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioOffloadInfo;
+
+namespace aidl::android::hardware::audio::core {
+
+DriverUsb::DriverUsb(const StreamContext& context, bool isInput)
+ : mFrameSizeBytes(context.getFrameSize()), mIsInput(isInput) {
+ struct pcm_config config;
+ config.channels = usb::getChannelCountFromChannelMask(context.getChannelLayout(), isInput);
+ if (config.channels == 0) {
+ LOG(ERROR) << __func__ << ": invalid channel=" << context.getChannelLayout().toString();
+ return;
+ }
+ config.format = usb::aidl2legacy_AudioFormatDescription_pcm_format(context.getFormat());
+ if (config.format == PCM_FORMAT_INVALID) {
+ LOG(ERROR) << __func__ << ": invalid format=" << context.getFormat().toString();
+ return;
+ }
+ config.rate = context.getSampleRate();
+ if (config.rate == 0) {
+ LOG(ERROR) << __func__ << ": invalid sample rate=" << config.rate;
+ return;
+ }
+ mConfig = config;
+}
+
+::android::status_t DriverUsb::init() {
+ return mConfig.has_value() ? ::android::OK : ::android::NO_INIT;
+}
+
+::android::status_t DriverUsb::setConnectedDevices(
+ const std::vector<AudioDevice>& connectedDevices) {
+ if (mIsInput && connectedDevices.size() > 1) {
+ LOG(ERROR) << __func__ << ": wrong device size(" << connectedDevices.size()
+ << ") for input stream";
+ return ::android::BAD_VALUE;
+ }
+ for (const auto& connectedDevice : connectedDevices) {
+ if (connectedDevice.address.getTag() != AudioDeviceAddress::alsa) {
+ LOG(ERROR) << __func__ << ": bad device address" << connectedDevice.address.toString();
+ return ::android::BAD_VALUE;
+ }
+ }
+ std::lock_guard guard(mLock);
+ mAlsaDeviceProxies.clear();
+ mConnectedDevices.clear();
+ for (const auto& connectedDevice : connectedDevices) {
+ mConnectedDevices.push_back(connectedDevice.address);
+ }
+ return ::android::OK;
+}
+
+::android::status_t DriverUsb::drain(StreamDescriptor::DrainMode) {
+ usleep(1000);
+ return ::android::OK;
+}
+
+::android::status_t DriverUsb::flush() {
+ usleep(1000);
+ return ::android::OK;
+}
+
+::android::status_t DriverUsb::pause() {
+ usleep(1000);
+ return ::android::OK;
+}
+
+::android::status_t DriverUsb::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
+ int32_t* latencyMs) {
+ if (!mConfig.has_value() || mConnectedDevices.empty()) {
+ return ::android::NO_INIT;
+ }
+ if (mIsStandby) {
+ if (::android::status_t status = exitStandby(); status != ::android::OK) {
+ return status;
+ }
+ }
+ std::vector<std::shared_ptr<alsa_device_proxy>> alsaDeviceProxies;
+ {
+ std::lock_guard guard(mLock);
+ alsaDeviceProxies = mAlsaDeviceProxies;
+ }
+ const size_t bytesToTransfer = frameCount * mFrameSizeBytes;
+ if (mIsInput) {
+ // For input case, only support single device.
+ proxy_read(alsaDeviceProxies[0].get(), buffer, bytesToTransfer);
+ } else {
+ for (auto& proxy : alsaDeviceProxies) {
+ proxy_write(proxy.get(), buffer, bytesToTransfer);
+ }
+ }
+ *actualFrameCount = frameCount;
+ *latencyMs = Module::kLatencyMs;
+ return ::android::OK;
+}
+
+::android::status_t DriverUsb::standby() {
+ if (!mIsStandby) {
+ std::lock_guard guard(mLock);
+ mAlsaDeviceProxies.clear();
+ mIsStandby = true;
+ }
+ return ::android::OK;
+}
+
+::android::status_t DriverUsb::exitStandby() {
+ std::vector<AudioDeviceAddress> connectedDevices;
+ {
+ std::lock_guard guard(mLock);
+ connectedDevices = mConnectedDevices;
+ }
+ std::vector<std::shared_ptr<alsa_device_proxy>> alsaDeviceProxies;
+ for (const auto& device : connectedDevices) {
+ alsa_device_profile profile;
+ profile.card = device.get<AudioDeviceAddress::alsa>()[0];
+ profile.device = device.get<AudioDeviceAddress::alsa>()[1];
+ if (!profile_read_device_info(&profile)) {
+ LOG(ERROR) << __func__
+ << ": unable to read device info, device address=" << device.toString();
+ return ::android::UNKNOWN_ERROR;
+ }
+
+ auto proxy = std::shared_ptr<alsa_device_proxy>(new alsa_device_proxy(),
+ [](alsa_device_proxy* proxy) {
+ proxy_close(proxy);
+ free(proxy);
+ });
+ // Always ask for alsa configure as required since the configuration should be supported
+ // by the connected device. That is guaranteed by `setAudioPortConfig` and
+ // `setAudioPatch`.
+ if (int err =
+ proxy_prepare(proxy.get(), &profile, &mConfig.value(), true /*is_bit_perfect*/);
+ err != 0) {
+ LOG(ERROR) << __func__ << ": fail to prepare for device address=" << device.toString()
+ << " error=" << err;
+ return ::android::UNKNOWN_ERROR;
+ }
+ alsaDeviceProxies.push_back(std::move(proxy));
+ }
+ {
+ std::lock_guard guard(mLock);
+ mAlsaDeviceProxies = alsaDeviceProxies;
+ }
+ mIsStandby = false;
+ return ::android::OK;
+}
+
+// static
+ndk::ScopedAStatus StreamInUsb::createInstance(const SinkMetadata& sinkMetadata,
+ StreamContext&& context,
+ const std::vector<MicrophoneInfo>& microphones,
+ std::shared_ptr<StreamIn>* result) {
+ std::shared_ptr<StreamIn> stream =
+ ndk::SharedRefBase::make<StreamInUsb>(sinkMetadata, std::move(context), microphones);
+ if (auto status = initInstance(stream); !status.isOk()) {
+ return status;
+ }
+ *result = std::move(stream);
+ return ndk::ScopedAStatus::ok();
+}
+
+StreamInUsb::StreamInUsb(const SinkMetadata& sinkMetadata, StreamContext&& context,
+ const std::vector<MicrophoneInfo>& microphones)
+ : StreamIn(
+ sinkMetadata, std::move(context),
+ [](const StreamContext& ctx) -> DriverInterface* {
+ return new DriverUsb(ctx, true /*isInput*/);
+ },
+ [](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* {
+ // The default worker implementation is used.
+ return new StreamInWorker(ctx, driver);
+ },
+ microphones) {}
+
+ndk::ScopedAStatus StreamInUsb::getActiveMicrophones(
+ std::vector<MicrophoneDynamicInfo>* _aidl_return __unused) {
+ LOG(DEBUG) << __func__ << ": not supported";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+// static
+ndk::ScopedAStatus StreamOutUsb::createInstance(const SourceMetadata& sourceMetadata,
+ StreamContext&& context,
+ const std::optional<AudioOffloadInfo>& offloadInfo,
+ std::shared_ptr<StreamOut>* result) {
+ if (offloadInfo.has_value()) {
+ LOG(ERROR) << __func__ << ": offload is not supported";
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ std::shared_ptr<StreamOut> stream =
+ ndk::SharedRefBase::make<StreamOutUsb>(sourceMetadata, std::move(context), offloadInfo);
+ if (auto status = initInstance(stream); !status.isOk()) {
+ return status;
+ }
+ *result = std::move(stream);
+ return ndk::ScopedAStatus::ok();
+}
+
+StreamOutUsb::StreamOutUsb(const SourceMetadata& sourceMetadata, StreamContext&& context,
+ const std::optional<AudioOffloadInfo>& offloadInfo)
+ : StreamOut(
+ sourceMetadata, std::move(context),
+ [](const StreamContext& ctx) -> DriverInterface* {
+ return new DriverUsb(ctx, false /*isInput*/);
+ },
+ [](const StreamContext& ctx, DriverInterface* driver) -> StreamWorkerInterface* {
+ // The default worker implementation is used.
+ return new StreamOutWorker(ctx, driver);
+ },
+ offloadInfo) {}
+
+} // namespace aidl::android::hardware::audio::core
\ No newline at end of file
diff --git a/audio/aidl/default/usb/UsbAlsaUtils.cpp b/audio/aidl/default/usb/UsbAlsaUtils.cpp
new file mode 100644
index 0000000..3c79e1d
--- /dev/null
+++ b/audio/aidl/default/usb/UsbAlsaUtils.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <map>
+#include <set>
+
+#include <Utils.h>
+#include <aidl/android/media/audio/common/AudioFormatType.h>
+#include <aidl/android/media/audio/common/PcmType.h>
+
+#include "UsbAlsaUtils.h"
+#include "core-impl/utils.h"
+
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioFormatDescription;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::PcmType;
+using android::hardware::audio::common::getChannelCount;
+
+namespace aidl::android::hardware::audio::core::usb {
+
+namespace {
+
+using AudioChannelCountToMaskMap = std::map<unsigned int, AudioChannelLayout>;
+using AudioFormatDescToPcmFormatMap = std::map<AudioFormatDescription, enum pcm_format>;
+using PcmFormatToAudioFormatDescMap = std::map<enum pcm_format, AudioFormatDescription>;
+
+static const AudioChannelLayout INVALID_CHANNEL_LAYOUT =
+ AudioChannelLayout::make<AudioChannelLayout::Tag::invalid>(0);
+
+#define DEFINE_CHANNEL_LAYOUT_MASK(n) \
+ AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(AudioChannelLayout::LAYOUT_##n)
+
+static const std::set<AudioChannelLayout> SUPPORTED_OUT_CHANNEL_LAYOUTS = {
+ DEFINE_CHANNEL_LAYOUT_MASK(MONO), DEFINE_CHANNEL_LAYOUT_MASK(STEREO),
+ DEFINE_CHANNEL_LAYOUT_MASK(2POINT1), DEFINE_CHANNEL_LAYOUT_MASK(QUAD),
+ DEFINE_CHANNEL_LAYOUT_MASK(PENTA), DEFINE_CHANNEL_LAYOUT_MASK(5POINT1),
+ DEFINE_CHANNEL_LAYOUT_MASK(6POINT1), DEFINE_CHANNEL_LAYOUT_MASK(7POINT1),
+ DEFINE_CHANNEL_LAYOUT_MASK(7POINT1POINT4), DEFINE_CHANNEL_LAYOUT_MASK(22POINT2),
+};
+
+static const std::set<AudioChannelLayout> SUPPORTED_IN_CHANNEL_LAYOUTS = {
+ DEFINE_CHANNEL_LAYOUT_MASK(MONO),
+ DEFINE_CHANNEL_LAYOUT_MASK(STEREO),
+};
+
+#define DEFINE_CHANNEL_INDEX_MASK(n) \
+ AudioChannelLayout::make<AudioChannelLayout::Tag::indexMask>(AudioChannelLayout::INDEX_MASK_##n)
+
+static const std::set<AudioChannelLayout> SUPPORTED_INDEX_CHANNEL_LAYOUTS = {
+ DEFINE_CHANNEL_INDEX_MASK(1), DEFINE_CHANNEL_INDEX_MASK(2), DEFINE_CHANNEL_INDEX_MASK(3),
+ DEFINE_CHANNEL_INDEX_MASK(4), DEFINE_CHANNEL_INDEX_MASK(5), DEFINE_CHANNEL_INDEX_MASK(6),
+ DEFINE_CHANNEL_INDEX_MASK(7), DEFINE_CHANNEL_INDEX_MASK(8), DEFINE_CHANNEL_INDEX_MASK(9),
+ DEFINE_CHANNEL_INDEX_MASK(10), DEFINE_CHANNEL_INDEX_MASK(11), DEFINE_CHANNEL_INDEX_MASK(12),
+ DEFINE_CHANNEL_INDEX_MASK(13), DEFINE_CHANNEL_INDEX_MASK(14), DEFINE_CHANNEL_INDEX_MASK(15),
+ DEFINE_CHANNEL_INDEX_MASK(16), DEFINE_CHANNEL_INDEX_MASK(17), DEFINE_CHANNEL_INDEX_MASK(18),
+ DEFINE_CHANNEL_INDEX_MASK(19), DEFINE_CHANNEL_INDEX_MASK(20), DEFINE_CHANNEL_INDEX_MASK(21),
+ DEFINE_CHANNEL_INDEX_MASK(22), DEFINE_CHANNEL_INDEX_MASK(23), DEFINE_CHANNEL_INDEX_MASK(24),
+};
+
+static AudioChannelCountToMaskMap make_ChannelCountToMaskMap(
+ const std::set<AudioChannelLayout>& channelMasks) {
+ AudioChannelCountToMaskMap channelMaskToCountMap;
+ for (const auto& channelMask : channelMasks) {
+ channelMaskToCountMap.emplace(getChannelCount(channelMask), channelMask);
+ }
+ return channelMaskToCountMap;
+}
+
+const AudioChannelCountToMaskMap& getSupportedChannelOutLayoutMap() {
+ static const AudioChannelCountToMaskMap outLayouts =
+ make_ChannelCountToMaskMap(SUPPORTED_OUT_CHANNEL_LAYOUTS);
+ return outLayouts;
+}
+
+const AudioChannelCountToMaskMap& getSupportedChannelInLayoutMap() {
+ static const AudioChannelCountToMaskMap inLayouts =
+ make_ChannelCountToMaskMap(SUPPORTED_IN_CHANNEL_LAYOUTS);
+ return inLayouts;
+}
+
+const AudioChannelCountToMaskMap& getSupportedChannelIndexLayoutMap() {
+ static const AudioChannelCountToMaskMap indexLayouts =
+ make_ChannelCountToMaskMap(SUPPORTED_INDEX_CHANNEL_LAYOUTS);
+ return indexLayouts;
+}
+
+AudioFormatDescription make_AudioFormatDescription(AudioFormatType type) {
+ AudioFormatDescription result;
+ result.type = type;
+ return result;
+}
+
+AudioFormatDescription make_AudioFormatDescription(PcmType pcm) {
+ auto result = make_AudioFormatDescription(AudioFormatType::PCM);
+ result.pcm = pcm;
+ return result;
+}
+
+const AudioFormatDescToPcmFormatMap& getAudioFormatDescriptorToPcmFormatMap() {
+ static const AudioFormatDescToPcmFormatMap formatDescToPcmFormatMap = {
+ {make_AudioFormatDescription(PcmType::UINT_8_BIT), PCM_FORMAT_S8},
+ {make_AudioFormatDescription(PcmType::INT_16_BIT), PCM_FORMAT_S16_LE},
+ {make_AudioFormatDescription(PcmType::INT_24_BIT), PCM_FORMAT_S24_LE},
+ {make_AudioFormatDescription(PcmType::FIXED_Q_8_24), PCM_FORMAT_S24_3LE},
+ {make_AudioFormatDescription(PcmType::INT_32_BIT), PCM_FORMAT_S32_LE},
+ {make_AudioFormatDescription(PcmType::FLOAT_32_BIT), PCM_FORMAT_FLOAT_LE},
+ };
+ return formatDescToPcmFormatMap;
+}
+
+static PcmFormatToAudioFormatDescMap make_PcmFormatToAudioFormatDescMap(
+ const AudioFormatDescToPcmFormatMap& formatDescToPcmFormatMap) {
+ PcmFormatToAudioFormatDescMap result;
+ for (const auto& formatPair : formatDescToPcmFormatMap) {
+ result.emplace(formatPair.second, formatPair.first);
+ }
+ return result;
+}
+
+const PcmFormatToAudioFormatDescMap& getPcmFormatToAudioFormatDescMap() {
+ static const PcmFormatToAudioFormatDescMap pcmFormatToFormatDescMap =
+ make_PcmFormatToAudioFormatDescMap(getAudioFormatDescriptorToPcmFormatMap());
+ return pcmFormatToFormatDescMap;
+}
+
+} // namespace
+
+AudioChannelLayout getChannelLayoutMaskFromChannelCount(unsigned int channelCount, int isInput) {
+ return findValueOrDefault(
+ isInput ? getSupportedChannelInLayoutMap() : getSupportedChannelOutLayoutMap(),
+ channelCount, INVALID_CHANNEL_LAYOUT);
+}
+
+AudioChannelLayout getChannelIndexMaskFromChannelCount(unsigned int channelCount) {
+ return findValueOrDefault(getSupportedChannelIndexLayoutMap(), channelCount,
+ INVALID_CHANNEL_LAYOUT);
+}
+
+unsigned int getChannelCountFromChannelMask(const AudioChannelLayout& channelMask, bool isInput) {
+ switch (channelMask.getTag()) {
+ case AudioChannelLayout::Tag::layoutMask: {
+ return findKeyOrDefault(
+ isInput ? getSupportedChannelInLayoutMap() : getSupportedChannelOutLayoutMap(),
+ (unsigned int)getChannelCount(channelMask), 0u /*defaultValue*/);
+ }
+ case AudioChannelLayout::Tag::indexMask: {
+ return findKeyOrDefault(getSupportedChannelIndexLayoutMap(),
+ (unsigned int)getChannelCount(channelMask),
+ 0u /*defaultValue*/);
+ }
+ case AudioChannelLayout::Tag::none:
+ case AudioChannelLayout::Tag::invalid:
+ case AudioChannelLayout::Tag::voiceMask:
+ default:
+ return 0;
+ }
+}
+
+AudioFormatDescription legacy2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy) {
+ return findValueOrDefault(getPcmFormatToAudioFormatDescMap(), legacy, AudioFormatDescription());
+}
+
+pcm_format aidl2legacy_AudioFormatDescription_pcm_format(const AudioFormatDescription& aidl) {
+ return findValueOrDefault(getAudioFormatDescriptorToPcmFormatMap(), aidl, PCM_FORMAT_INVALID);
+}
+
+} // namespace aidl::android::hardware::audio::core::usb
\ No newline at end of file
diff --git a/audio/aidl/default/usb/UsbAlsaUtils.h b/audio/aidl/default/usb/UsbAlsaUtils.h
new file mode 100644
index 0000000..2d2f0f4
--- /dev/null
+++ b/audio/aidl/default/usb/UsbAlsaUtils.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/media/audio/common/AudioChannelLayout.h>
+#include <aidl/android/media/audio/common/AudioFormatDescription.h>
+
+extern "C" {
+#include <tinyalsa/pcm.h>
+}
+
+namespace aidl::android::hardware::audio::core::usb {
+
+::aidl::android::media::audio::common::AudioChannelLayout getChannelLayoutMaskFromChannelCount(
+ unsigned int channelCount, int isInput);
+::aidl::android::media::audio::common::AudioChannelLayout getChannelIndexMaskFromChannelCount(
+ unsigned int channelCount);
+unsigned int getChannelCountFromChannelMask(
+ const ::aidl::android::media::audio::common::AudioChannelLayout& channelMask, bool isInput);
+::aidl::android::media::audio::common::AudioFormatDescription
+legacy2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy);
+pcm_format aidl2legacy_AudioFormatDescription_pcm_format(
+ const ::aidl::android::media::audio::common::AudioFormatDescription& aidl);
+
+} // namespace aidl::android::hardware::audio::core::usb
\ No newline at end of file
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.cpp b/audio/aidl/default/virtualizer/VirtualizerSw.cpp
index cc51937..08535bd 100644
--- a/audio/aidl/default/virtualizer/VirtualizerSw.cpp
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.cpp
@@ -30,6 +30,8 @@
using aidl::android::hardware::audio::effect::kVirtualizerSwImplUUID;
using aidl::android::hardware::audio::effect::State;
using aidl::android::hardware::audio::effect::VirtualizerSw;
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioDeviceDescription;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
@@ -93,10 +95,18 @@
RETURN_IF(mContext->setVrStrength(vrParam.get<Virtualizer::strengthPm>()) !=
RetCode::SUCCESS,
- EX_ILLEGAL_ARGUMENT, "strengthPmNotSupported");
+ EX_ILLEGAL_ARGUMENT, "setStrengthPmFailed");
return ndk::ScopedAStatus::ok();
}
- default: {
+ case Virtualizer::device: {
+ RETURN_IF(mContext->setForcedDevice(vrParam.get<Virtualizer::device>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setDeviceFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case Virtualizer::speakerAngles:
+ FALLTHROUGH_INTENDED;
+ case Virtualizer::vendor: {
LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"VirtualizerTagNotSupported");
@@ -113,10 +123,13 @@
switch (vrIdTag) {
case Virtualizer::Id::commonTag:
return getParameterVirtualizer(vrId.get<Virtualizer::Id::commonTag>(), specific);
- default:
+ case Virtualizer::Id::speakerAnglesPayload:
+ return getSpeakerAngles(vrId.get<Virtualizer::Id::speakerAnglesPayload>(), specific);
+ case Virtualizer::Id::vendorExtensionTag: {
LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"VirtualizerTagNotSupported");
+ }
}
}
@@ -130,7 +143,13 @@
vrParam.set<Virtualizer::strengthPm>(mContext->getVrStrength());
break;
}
- default: {
+ case Virtualizer::device: {
+ vrParam.set<Virtualizer::device>(mContext->getForcedDevice());
+ break;
+ }
+ case Virtualizer::speakerAngles:
+ FALLTHROUGH_INTENDED;
+ case Virtualizer::vendor: {
LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"VirtualizerTagNotSupported");
@@ -141,6 +160,27 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus VirtualizerSw::getSpeakerAngles(const Virtualizer::SpeakerAnglesPayload payload,
+ Parameter::Specific* specific) {
+ std::vector<Virtualizer::ChannelAngle> angles;
+ if (::android::hardware::audio::common::getChannelCount(payload.layout) == 1) {
+ angles = {{.channel = (int32_t)AudioChannelLayout::CHANNEL_FRONT_LEFT,
+ .azimuthDegree = 0,
+ .elevationDegree = 0}};
+ } else {
+ angles = {{.channel = (int32_t)AudioChannelLayout::CHANNEL_FRONT_LEFT,
+ .azimuthDegree = -90,
+ .elevationDegree = 0},
+ {.channel = (int32_t)AudioChannelLayout::CHANNEL_FRONT_RIGHT,
+ .azimuthDegree = 90,
+ .elevationDegree = 0}};
+ }
+
+ Virtualizer param = Virtualizer::make<Virtualizer::speakerAngles>(angles);
+ specific->set<Parameter::Specific::virtualizer>(param);
+ return ndk::ScopedAStatus::ok();
+}
+
std::shared_ptr<EffectContext> VirtualizerSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.h b/audio/aidl/default/virtualizer/VirtualizerSw.h
index 0f294cd..1016ffc 100644
--- a/audio/aidl/default/virtualizer/VirtualizerSw.h
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.h
@@ -34,9 +34,18 @@
}
RetCode setVrStrength(int strength);
int getVrStrength() const { return mStrength; }
+ RetCode setForcedDevice(
+ const ::aidl::android::media::audio::common::AudioDeviceDescription& device) {
+ mForceDevice = device;
+ return RetCode::SUCCESS;
+ }
+ aidl::android::media::audio::common::AudioDeviceDescription getForcedDevice() const {
+ return mForceDevice;
+ }
private:
int mStrength = 0;
+ ::aidl::android::media::audio::common::AudioDeviceDescription mForceDevice;
};
class VirtualizerSw final : public EffectImpl {
@@ -68,5 +77,7 @@
ndk::ScopedAStatus getParameterVirtualizer(const Virtualizer::Tag& tag,
Parameter::Specific* specific);
+ ndk::ScopedAStatus getSpeakerAngles(const Virtualizer::SpeakerAnglesPayload payload,
+ Parameter::Specific* specific);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/vts/EffectHelper.h b/audio/aidl/vts/EffectHelper.h
index 7222d4f..526a012 100644
--- a/audio/aidl/vts/EffectHelper.h
+++ b/audio/aidl/vts/EffectHelper.h
@@ -148,16 +148,22 @@
}
static void readFromFmq(std::unique_ptr<StatusMQ>& statusMq, size_t statusNum,
std::unique_ptr<DataMQ>& dataMq, size_t expectFloats,
- std::vector<float>& buffer) {
+ std::vector<float>& buffer,
+ std::optional<int> expectStatus = STATUS_OK) {
+ if (0 == statusNum) {
+ ASSERT_EQ(0ul, statusMq->availableToRead());
+ return;
+ }
IEffect::Status status{};
ASSERT_TRUE(statusMq->readBlocking(&status, statusNum));
- ASSERT_EQ(STATUS_OK, status.status);
- if (statusNum != 0) {
- ASSERT_EQ(expectFloats, (unsigned)status.fmqProduced);
- ASSERT_EQ(expectFloats, dataMq->availableToRead());
- if (expectFloats != 0) {
- ASSERT_TRUE(dataMq->read(buffer.data(), expectFloats));
- }
+ if (expectStatus.has_value()) {
+ ASSERT_EQ(expectStatus.value(), status.status);
+ }
+
+ ASSERT_EQ(expectFloats, (unsigned)status.fmqProduced);
+ ASSERT_EQ(expectFloats, dataMq->availableToRead());
+ if (expectFloats != 0) {
+ ASSERT_TRUE(dataMq->read(buffer.data(), expectFloats));
}
}
static Parameter::Common createParamCommon(
diff --git a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
index c5a0943..88bdd13 100644
--- a/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioEffectTargetTest.cpp
@@ -590,12 +590,14 @@
ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
std::vector<float> buffer;
- EffectHelper::allocateInputData(common, inputMQ, buffer);
- EffectHelper::writeToFmq(inputMQ, buffer);
- EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(inputMQ, buffer));
+ EXPECT_NO_FATAL_FAILURE(
+ EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer));
ASSERT_NO_FATAL_FAILURE(close(mEffect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
@@ -617,20 +619,24 @@
auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
ASSERT_TRUE(outputMQ->isValid());
- ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
- ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
- ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
- ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
- ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
-
std::vector<float> buffer;
- EffectHelper::allocateInputData(common, inputMQ, buffer);
- EffectHelper::writeToFmq(inputMQ, buffer);
- EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ EXPECT_NO_FATAL_FAILURE(
+ EffectHelper::readFromFmq(statusMQ, 0, outputMQ, buffer.size(), buffer));
+ ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
+ ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(inputMQ, buffer));
+ EXPECT_NO_FATAL_FAILURE(
+ EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer));
ASSERT_NO_FATAL_FAILURE(close(mEffect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
@@ -653,14 +659,14 @@
ASSERT_TRUE(outputMQ->isValid());
std::vector<float> buffer;
- EffectHelper::allocateInputData(common, inputMQ, buffer);
- EffectHelper::writeToFmq(inputMQ, buffer);
- EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(inputMQ, buffer));
ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
- EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
+ EXPECT_NO_FATAL_FAILURE(
+ EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
@@ -686,31 +692,30 @@
ASSERT_TRUE(outputMQ->isValid());
std::vector<float> buffer;
- EffectHelper::allocateInputData(common, inputMQ, buffer);
- EffectHelper::writeToFmq(inputMQ, buffer);
- EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(inputMQ, buffer));
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer));
ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
- EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
- // expect no status and data after consume
- EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
+ EXPECT_NO_FATAL_FAILURE(
+ EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
- EffectHelper::writeToFmq(inputMQ, buffer);
- EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
- // expect no status and data after consume
- EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(inputMQ, buffer));
+ EXPECT_NO_FATAL_FAILURE(
+ EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer));
ASSERT_NO_FATAL_FAILURE(close(mEffect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
-// Send data to IDLE state effects and expect it not be consumed.
-TEST_P(AudioEffectTest, NotConsumeDataInIdleState) {
+// Send data to processing state effects, stop, and restart.
+TEST_P(AudioEffectTest, ConsumeDataAndRestart) {
ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
Parameter::Common common = EffectHelper::createParamCommon(
@@ -727,17 +732,21 @@
ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
+ std::vector<float> buffer;
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(inputMQ, buffer));
+ EXPECT_NO_FATAL_FAILURE(
+ EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
+
ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
-
- std::vector<float> buffer;
- EffectHelper::allocateInputData(common, inputMQ, buffer);
- EffectHelper::writeToFmq(inputMQ, buffer);
- EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(inputMQ, buffer));
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer));
ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::PROCESSING));
- EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
+ EXPECT_NO_FATAL_FAILURE(
+ EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer));
ASSERT_NO_FATAL_FAILURE(command(mEffect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(mEffect, State::IDLE));
@@ -765,9 +774,9 @@
ASSERT_TRUE(outputMQ->isValid());
std::vector<float> buffer;
- EffectHelper::allocateInputData(common, inputMQ, buffer);
- EffectHelper::writeToFmq(inputMQ, buffer);
- EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common, inputMQ, buffer));
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(inputMQ, buffer));
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
@@ -800,9 +809,10 @@
ASSERT_TRUE(outputMQ1->isValid());
std::vector<float> buffer1, buffer2;
- EffectHelper::allocateInputData(common1, inputMQ1, buffer1);
- EffectHelper::writeToFmq(inputMQ1, buffer1);
- EffectHelper::readFromFmq(statusMQ1, 1, outputMQ1, buffer1.size(), buffer1);
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common1, inputMQ1, buffer1));
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(inputMQ1, buffer1));
+ EXPECT_NO_FATAL_FAILURE(
+ EffectHelper::readFromFmq(statusMQ1, 1, outputMQ1, buffer1.size(), buffer1));
auto statusMQ2 = std::make_unique<EffectHelper::StatusMQ>(ret2.statusMQ);
ASSERT_TRUE(statusMQ2->isValid());
@@ -810,9 +820,10 @@
ASSERT_TRUE(inputMQ2->isValid());
auto outputMQ2 = std::make_unique<EffectHelper::DataMQ>(ret2.outputDataMQ);
ASSERT_TRUE(outputMQ2->isValid());
- EffectHelper::allocateInputData(common2, inputMQ2, buffer2);
- EffectHelper::writeToFmq(inputMQ2, buffer2);
- EffectHelper::readFromFmq(statusMQ2, 1, outputMQ2, buffer2.size(), buffer2);
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::allocateInputData(common2, inputMQ2, buffer2));
+ EXPECT_NO_FATAL_FAILURE(EffectHelper::writeToFmq(inputMQ2, buffer2));
+ EXPECT_NO_FATAL_FAILURE(
+ EffectHelper::readFromFmq(statusMQ2, 1, outputMQ2, buffer2.size(), buffer2));
ASSERT_NO_FATAL_FAILURE(command(effect1, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(effect1, State::IDLE));
diff --git a/audio/aidl/vts/VtsHalNSTargetTest.cpp b/audio/aidl/vts/VtsHalNSTargetTest.cpp
index 93ad86d..0b92290 100644
--- a/audio/aidl/vts/VtsHalNSTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalNSTargetTest.cpp
@@ -34,13 +34,14 @@
using aidl::android::hardware::audio::effect::NoiseSuppression;
using aidl::android::hardware::audio::effect::Parameter;
-enum ParamName { PARAM_INSTANCE_NAME, PARAM_LEVEL };
-using NSParamTestParam =
- std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, NoiseSuppression::Level>;
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_LEVEL, PARAM_TYPE };
+using NSParamTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
+ NoiseSuppression::Level, NoiseSuppression::Type>;
class NSParamTest : public ::testing::TestWithParam<NSParamTestParam>, public EffectHelper {
public:
- NSParamTest() : mLevel(std::get<PARAM_LEVEL>(GetParam())) {
+ NSParamTest()
+ : mLevel(std::get<PARAM_LEVEL>(GetParam())), mType(std::get<PARAM_TYPE>(GetParam())) {
std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
}
@@ -75,6 +76,7 @@
std::shared_ptr<IEffect> mEffect;
Descriptor mDescriptor;
NoiseSuppression::Level mLevel;
+ NoiseSuppression::Type mType;
void SetAndGetParameters() {
for (auto& it : mTags) {
@@ -113,10 +115,19 @@
ns.set<NoiseSuppression::level>(level);
mTags.push_back({NoiseSuppression::level, ns});
}
+ void addTypeParam(NoiseSuppression::Type type) {
+ NoiseSuppression ns;
+ ns.set<NoiseSuppression::type>(type);
+ mTags.push_back({NoiseSuppression::type, ns});
+ }
static std::unordered_set<NoiseSuppression::Level> getLevelValues() {
return {ndk::enum_range<NoiseSuppression::Level>().begin(),
ndk::enum_range<NoiseSuppression::Level>().end()};
}
+ static std::unordered_set<NoiseSuppression::Type> getTypeValues() {
+ return {ndk::enum_range<NoiseSuppression::Type>().begin(),
+ ndk::enum_range<NoiseSuppression::Type>().end()};
+ }
private:
std::vector<std::pair<NoiseSuppression::Tag, NoiseSuppression>> mTags;
@@ -128,18 +139,27 @@
SetAndGetParameters();
}
+TEST_P(NSParamTest, SetAndGetType) {
+ EXPECT_NO_FATAL_FAILURE(addLevelParam(mLevel));
+ SetAndGetParameters();
+}
+
INSTANTIATE_TEST_SUITE_P(
NSParamTest, NSParamTest,
::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
IFactory::descriptor, kNoiseSuppressionTypeUUID)),
- testing::ValuesIn(NSParamTest::getLevelValues())),
+ testing::ValuesIn(NSParamTest::getLevelValues()),
+ testing::ValuesIn(NSParamTest::getTypeValues())),
[](const testing::TestParamInfo<NSParamTest::ParamType>& info) {
auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
std::string level = aidl::android::hardware::audio::effect::toString(
std::get<PARAM_LEVEL>(info.param));
+ std::string type = aidl::android::hardware::audio::effect::toString(
+ std::get<PARAM_TYPE>(info.param));
std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
descriptor.common.name + "_UUID_" +
- descriptor.common.id.uuid.toString() + "_level_" + level;
+ descriptor.common.id.uuid.toString() + "_level_" + level + "_type_" +
+ type;
std::replace_if(
name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
return name;
diff --git a/bluetooth/aidl/android/hardware/bluetooth/IBluetoothHci.aidl b/bluetooth/aidl/android/hardware/bluetooth/IBluetoothHci.aidl
index db12986..ff1f735 100644
--- a/bluetooth/aidl/android/hardware/bluetooth/IBluetoothHci.aidl
+++ b/bluetooth/aidl/android/hardware/bluetooth/IBluetoothHci.aidl
@@ -35,6 +35,9 @@
/**
* Initialize the Bluetooth interface and set the callbacks.
+ * Only one client can initialize the interface at a time. When a
+ * call to initialize fails, the Status parameter of the callback
+ * will indicate the reason for the failure.
*/
void initialize(in IBluetoothHciCallbacks callback);
diff --git a/bluetooth/aidl/android/hardware/bluetooth/IBluetoothHciCallbacks.aidl b/bluetooth/aidl/android/hardware/bluetooth/IBluetoothHciCallbacks.aidl
index 000333e..0148c6f 100644
--- a/bluetooth/aidl/android/hardware/bluetooth/IBluetoothHciCallbacks.aidl
+++ b/bluetooth/aidl/android/hardware/bluetooth/IBluetoothHciCallbacks.aidl
@@ -39,6 +39,8 @@
/**
* Invoked when the Bluetooth controller initialization has been
* completed.
+ * @param status contains a return code indicating success, or the
+ * reason the initialization failed.
*/
void initializationComplete(in Status status);
diff --git a/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp b/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp
index 7b9e211..3704c3d 100644
--- a/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp
+++ b/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp
@@ -867,6 +867,48 @@
wait_for_command_complete_event(set_event_mask);
}
+// Call initialize twice, second one should fail.
+TEST_P(BluetoothAidlTest, CallInitializeTwice) {
+ class SecondCb
+ : public aidl::android::hardware::bluetooth::BnBluetoothHciCallbacks {
+ public:
+ ndk::ScopedAStatus initializationComplete(Status status) {
+ EXPECT_EQ(status, Status::ALREADY_INITIALIZED);
+ init_promise.set_value();
+ return ScopedAStatus::ok();
+ };
+
+ ndk::ScopedAStatus hciEventReceived(const std::vector<uint8_t>& /*event*/) {
+ ADD_FAILURE();
+ return ScopedAStatus::ok();
+ };
+
+ ndk::ScopedAStatus aclDataReceived(const std::vector<uint8_t>& /*data*/) {
+ ADD_FAILURE();
+ return ScopedAStatus::ok();
+ };
+
+ ndk::ScopedAStatus scoDataReceived(const std::vector<uint8_t>& /*data*/) {
+ ADD_FAILURE();
+ return ScopedAStatus::ok();
+ };
+
+ ndk::ScopedAStatus isoDataReceived(const std::vector<uint8_t>& /*data*/) {
+ ADD_FAILURE();
+ return ScopedAStatus::ok();
+ };
+ std::promise<void> init_promise;
+ };
+
+ std::shared_ptr<SecondCb> second_cb = ndk::SharedRefBase::make<SecondCb>();
+ ASSERT_NE(second_cb, nullptr);
+
+ auto future = second_cb->init_promise.get_future();
+ ASSERT_TRUE(hci->initialize(second_cb).isOk());
+ auto status = future.wait_for(std::chrono::seconds(1));
+ ASSERT_EQ(status, std::future_status::ready);
+}
+
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(BluetoothAidlTest);
INSTANTIATE_TEST_SUITE_P(PerInstance, BluetoothAidlTest,
testing::ValuesIn(android::getAidlHalInstanceNames(
diff --git a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
index e9b74b7..128ef61 100644
--- a/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
+++ b/bluetooth/audio/aidl/vts/VtsHalBluetoothAudioTargetTest.cpp
@@ -1566,6 +1566,7 @@
};
for (auto& lc3_config : lc3_codec_configs) {
+ le_audio_broadcast_config.streamMap.resize(1);
le_audio_broadcast_config.streamMap[0]
.leAudioCodecConfig.set<LeAudioCodecConfiguration::lc3Config>(
lc3_config);
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
index 1dec900..0a804bb 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.cpp
@@ -200,13 +200,21 @@
GetUnicastCapability(scenario.getEncode());
UnicastCapability unicast_decode_capability =
GetUnicastCapability(scenario.getDecode());
- // encode and decode cannot be unknown at the same time
- if (unicast_encode_capability.codecType == CodecType::UNKNOWN &&
- unicast_decode_capability.codecType == CodecType::UNKNOWN) {
- continue;
- }
BroadcastCapability broadcast_capability = {.codecType =
CodecType::UNKNOWN};
+
+ if (scenario.hasBroadcast()) {
+ broadcast_capability = GetBroadcastCapability(scenario.getBroadcast());
+ }
+
+ // At least one capability should be valid
+ if (unicast_encode_capability.codecType == CodecType::UNKNOWN &&
+ unicast_decode_capability.codecType == CodecType::UNKNOWN &&
+ broadcast_capability.codecType == CodecType::UNKNOWN) {
+ LOG(ERROR) << __func__ << ": None of the capability is valid.";
+ continue;
+ }
+
le_audio_codec_capabilities.push_back(
{.unicastEncodeCapability = unicast_encode_capability,
.unicastDecodeCapability = unicast_decode_capability,
@@ -252,6 +260,54 @@
return {.codecType = CodecType::UNKNOWN};
}
+BroadcastCapability BluetoothLeAudioCodecsProvider::GetBroadcastCapability(
+ const std::string& coding_direction) {
+ if (coding_direction == "invalid") {
+ return {.codecType = CodecType::UNKNOWN};
+ }
+
+ auto configuration_iter = configuration_map_.find(coding_direction);
+ if (configuration_iter == configuration_map_.end()) {
+ return {.codecType = CodecType::UNKNOWN};
+ }
+
+ auto codec_configuration_iter = codec_configuration_map_.find(
+ configuration_iter->second.getCodecConfiguration());
+ if (codec_configuration_iter == codec_configuration_map_.end()) {
+ return {.codecType = CodecType::UNKNOWN};
+ }
+
+ auto strategy_configuration_iter = strategy_configuration_map_.find(
+ configuration_iter->second.getStrategyConfiguration());
+ if (strategy_configuration_iter == strategy_configuration_map_.end()) {
+ return {.codecType = CodecType::UNKNOWN};
+ }
+
+ CodecType codec_type =
+ GetCodecType(codec_configuration_iter->second.getCodec());
+ std::vector<std::optional<Lc3Capabilities>> bcastLc3Cap(
+ 1, std::optional(ComposeLc3Capability(codec_configuration_iter->second)));
+
+ if (codec_type == CodecType::LC3) {
+ return ComposeBroadcastCapability(
+ codec_type,
+ GetAudioLocation(
+ strategy_configuration_iter->second.getAudioLocation()),
+ strategy_configuration_iter->second.getChannelCount(), bcastLc3Cap);
+ }
+ return {.codecType = CodecType::UNKNOWN};
+}
+
+template <class T>
+BroadcastCapability BluetoothLeAudioCodecsProvider::ComposeBroadcastCapability(
+ const CodecType& codec_type, const AudioLocation& audio_location,
+ const uint8_t& channel_count, const std::vector<T>& capability) {
+ return {.codecType = codec_type,
+ .supportedChannel = audio_location,
+ .channelCountPerStream = channel_count,
+ .leAudioCodecCapabilities = std::optional(capability)};
+}
+
template <class T>
UnicastCapability BluetoothLeAudioCodecsProvider::ComposeUnicastCapability(
const CodecType& codec_type, const AudioLocation& audio_location,
@@ -322,6 +378,10 @@
// 1. two connected device, one for L one for R
// 2. one connected device for both L and R
return true;
+ } else if (strategy_configuration.getConnectedDevice() == 0 &&
+ strategy_configuration.getChannelCount() == 2) {
+ // Broadcast
+ return true;
}
} else if (strategy_configuration.getAudioLocation() ==
setting::AudioLocation::MONO) {
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
index e879984..06e4595 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProvider.h
@@ -20,6 +20,7 @@
#include <android-base/logging.h>
#include <unordered_map>
+#include <vector>
#include "aidl_android_hardware_bluetooth_audio_setting.h"
@@ -66,12 +67,20 @@
static UnicastCapability GetUnicastCapability(
const std::string& coding_direction);
+ static BroadcastCapability GetBroadcastCapability(
+ const std::string& coding_direction);
+
template <class T>
static inline UnicastCapability ComposeUnicastCapability(
const CodecType& codec_type, const AudioLocation& audio_location,
const uint8_t& device_cnt, const uint8_t& channel_count,
const T& capability);
+ template <class T>
+ static inline BroadcastCapability ComposeBroadcastCapability(
+ const CodecType& codec_type, const AudioLocation& audio_location,
+ const uint8_t& channel_count, const std::vector<T>& capability);
+
static inline Lc3Capabilities ComposeLc3Capability(
const setting::CodecConfiguration& codec_configuration);
diff --git a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp
index 5393cd7..dba2749 100644
--- a/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp
+++ b/bluetooth/audio/utils/aidl_session/BluetoothLeAudioCodecsProviderTest.cpp
@@ -46,7 +46,11 @@
// Define valid components for each list
// Scenario
static const Scenario kValidScenario(std::make_optional("OneChanStereo_16_1"),
- std::make_optional("OneChanStereo_16_1"));
+ std::make_optional("OneChanStereo_16_1"),
+ std::nullopt);
+static const Scenario kValidBroadcastScenario(
+ std::nullopt, std::nullopt, std::make_optional("BcastStereo_16_2"));
+
// Configuration
static const Configuration kValidConfigOneChanStereo_16_1(
std::make_optional("OneChanStereo_16_1"), std::make_optional("LC3_16k_1"),
@@ -69,11 +73,15 @@
std::make_optional("MONO_ONE_CIS_PER_DEVICE"),
std::make_optional(AudioLocation::MONO), std::make_optional(1),
std::make_optional(1));
+static const StrategyConfiguration kValidStrategyBroadcastStereo(
+ std::make_optional("BROADCAST_STEREO"),
+ std::make_optional(AudioLocation::STEREO), std::make_optional(0),
+ std::make_optional(2));
// Define valid test list built from above valid components
// Scenario, Configuration, CodecConfiguration, StrategyConfiguration
-static const std::vector<ScenarioList> kValidScenarioList = {
- ScenarioList(std::vector<Scenario>{kValidScenario})};
+static const std::vector<ScenarioList> kValidScenarioList = {ScenarioList(
+ std::vector<Scenario>{kValidScenario, kValidBroadcastScenario})};
static const std::vector<ConfigurationList> kValidConfigurationList = {
ConfigurationList(
std::vector<Configuration>{kValidConfigOneChanStereo_16_1})};
@@ -84,7 +92,7 @@
kValidStrategyConfigurationList = {
StrategyConfigurationList(std::vector<StrategyConfiguration>{
kValidStrategyStereoOneCis, kValidStrategyStereoTwoCis,
- kValidStrategyMonoOneCis})};
+ kValidStrategyMonoOneCis, kValidStrategyBroadcastStereo})};
class BluetoothLeAudioCodecsProviderTest
: public ::testing::TestWithParam<OffloadSetting> {
@@ -151,13 +159,15 @@
static std::vector<ScenarioList> CreateInvalidScenarios() {
std::vector<ScenarioList> invalid_scenario_test_cases;
invalid_scenario_test_cases.push_back(ScenarioList(std::vector<Scenario>{
- Scenario(std::nullopt, std::make_optional("OneChanStereo_16_1"))}));
-
- invalid_scenario_test_cases.push_back(ScenarioList(std::vector<Scenario>{
- Scenario(std::make_optional("OneChanStereo_16_1"), std::nullopt)}));
+ Scenario(std::nullopt, std::make_optional("OneChanStereo_16_1"),
+ std::nullopt)}));
invalid_scenario_test_cases.push_back(ScenarioList(
- std::vector<Scenario>{Scenario(std::nullopt, std::nullopt)}));
+ std::vector<Scenario>{Scenario(std::make_optional("OneChanStereo_16_1"),
+ std::nullopt, std::nullopt)}));
+
+ invalid_scenario_test_cases.push_back(ScenarioList(std::vector<Scenario>{
+ Scenario(std::nullopt, std::nullopt, std::nullopt)}));
invalid_scenario_test_cases.push_back(
ScenarioList(std::vector<Scenario>{}));
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml
index c7904b3..c8d1af0 100644
--- a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xml
@@ -40,6 +40,8 @@
<scenario encode="OneChanStereo_16_2" decode="OneChanMono_16_2"/>
<scenario encode="TwoChanStereo_16_2" decode="OneChanMono_16_2"/>
<scenario encode="OneChanMono_16_2" decode="OneChanMono_16_2"/>
+ <!-- broadcast -->
+ <scenario encode="invalid" decode="invalid" broadcast="BcastStereo_16_2"/>
</scenarioList>
<configurationList>
<configuration name="OneChanMono_16_1" codecConfiguration="LC3_16k_1" strategyConfiguration="MONO_ONE_CIS_PER_DEVICE"/>
@@ -48,6 +50,7 @@
<configuration name="OneChanMono_16_2" codecConfiguration="LC3_16k_2" strategyConfiguration="MONO_ONE_CIS_PER_DEVICE"/>
<configuration name="TwoChanStereo_16_2" codecConfiguration="LC3_16k_2" strategyConfiguration="STEREO_TWO_CISES_PER_DEVICE"/>
<configuration name="OneChanStereo_16_2" codecConfiguration="LC3_16k_2" strategyConfiguration="STEREO_ONE_CIS_PER_DEVICE"/>
+ <configuration name="BcastStereo_16_2" codecConfiguration="LC3_16k_2" strategyConfiguration="BROADCAST_STEREO"/>
</configurationList>
<codecConfigurationList>
<codecConfiguration name="LC3_16k_1" codec="LC3" samplingFrequency="16000" frameDurationUs="7500" octetsPerCodecFrame="30"/>
@@ -57,5 +60,6 @@
<strategyConfiguration name="STEREO_ONE_CIS_PER_DEVICE" audioLocation="STEREO" connectedDevice="2" channelCount="1"/>
<strategyConfiguration name="STEREO_TWO_CISES_PER_DEVICE" audioLocation="STEREO" connectedDevice="1" channelCount="2"/>
<strategyConfiguration name="MONO_ONE_CIS_PER_DEVICE" audioLocation="MONO" connectedDevice="1" channelCount="1"/>
+ <strategyConfiguration name="BROADCAST_STEREO" audioLocation="STEREO" connectedDevice="0" channelCount="2"/>
</strategyConfigurationList>
</leAudioOffloadSetting>
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd
index 213e597..8c2d6a1 100644
--- a/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/le_audio_codec_capabilities.xsd
@@ -32,6 +32,7 @@
<xs:complexType>
<xs:attribute name="encode" type="xs:string"/>
<xs:attribute name="decode" type="xs:string"/>
+ <xs:attribute name="broadcast" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="configuration">
diff --git a/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt
index 06aa21a..886350e 100644
--- a/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt
+++ b/bluetooth/audio/utils/le_audio_codec_capabilities/schema/current.txt
@@ -64,8 +64,10 @@
public class Scenario {
ctor public Scenario();
+ method public String getBroadcast();
method public String getDecode();
method public String getEncode();
+ method public void setBroadcast(String);
method public void setDecode(String);
method public void setEncode(String);
}
diff --git a/bluetooth/hci/test/h4_protocol_unittest.cc b/bluetooth/hci/test/h4_protocol_unittest.cc
index d6f74fc..d3fab61 100644
--- a/bluetooth/hci/test/h4_protocol_unittest.cc
+++ b/bluetooth/hci/test/h4_protocol_unittest.cc
@@ -50,6 +50,9 @@
static char iso_data[100] =
"A plane angle is the inclination to one another of two lines in a ...";
+// 5 seconds. Just don't hang.
+static constexpr size_t kTimeoutMs = 5000;
+
MATCHER_P3(PacketMatches, header_, header_length, payload,
"Match header_length bytes of header and then the payload") {
size_t payload_length = strlen(payload);
@@ -131,9 +134,9 @@
.WillOnce(Notify(promise));
}
- void WaitForTimeout(size_t timeout_ms, std::promise<void>* promise) {
+ void WaitForTimeout(std::promise<void>* promise) {
auto future = promise->get_future();
- auto status = future.wait_for(std::chrono::milliseconds(timeout_ms));
+ auto status = future.wait_for(std::chrono::milliseconds(kTimeoutMs));
EXPECT_EQ(status, std::future_status::ready);
}
@@ -263,10 +266,10 @@
WriteInboundIsoData(iso_data);
CallDataReady();
- WaitForTimeout(100, &acl_promise);
- WaitForTimeout(100, &sco_promise);
- WaitForTimeout(100, &event_promise);
- WaitForTimeout(100, &iso_promise);
+ WaitForTimeout(&acl_promise);
+ WaitForTimeout(&sco_promise);
+ WaitForTimeout(&event_promise);
+ WaitForTimeout(&iso_promise);
}
TEST_F(H4ProtocolTest, TestMultiplePackets) {
@@ -363,28 +366,28 @@
std::promise<void> promise;
ExpectInboundAclData(payload, &promise);
WriteInboundAclData(payload);
- WaitForTimeout(100, &promise);
+ WaitForTimeout(&promise);
}
void WriteAndExpectInboundScoData(char* payload) {
std::promise<void> promise;
ExpectInboundScoData(payload, &promise);
WriteInboundScoData(payload);
- WaitForTimeout(100, &promise);
+ WaitForTimeout(&promise);
}
void WriteAndExpectInboundEvent(char* payload) {
std::promise<void> promise;
ExpectInboundEvent(payload, &promise);
WriteInboundEvent(payload);
- WaitForTimeout(100, &promise);
+ WaitForTimeout(&promise);
}
void WriteAndExpectInboundIsoData(char* payload) {
std::promise<void> promise;
ExpectInboundIsoData(payload, &promise);
WriteInboundIsoData(payload);
- WaitForTimeout(100, &promise);
+ WaitForTimeout(&promise);
}
void WriteAndExpectManyInboundAclDataPackets(char* payload) {
@@ -436,6 +439,5 @@
EXPECT_CALL(disconnect_cb_, Call()).WillOnce(Notify(&promise));
close(chip_uart_fd_);
- // Fail if it takes longer than 100 ms.
- WaitForTimeout(100, &promise);
+ WaitForTimeout(&promise);
}
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index b0ae20e..5ea6ae2 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -6318,8 +6318,6 @@
std::vector<AvailableStream>& outputStreams,
const AvailableStream* threshold,
bool maxResolution) {
- AvailableStream depthPreviewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
- static_cast<int32_t>(PixelFormat::Y16)};
if (nullptr == staticMeta) {
return Status::ILLEGAL_ARGUMENT;
}
@@ -6345,8 +6343,12 @@
}
if(foundDepth == 0 && (0 == (depthEntry.count % 4))) {
- fillOutputStreams(&depthEntry, outputStreams, &depthPreviewThreshold,
- ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_OUTPUT);
+ AvailableStream depthPreviewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+ static_cast<int32_t>(PixelFormat::Y16)};
+ const AvailableStream* depthThreshold =
+ (threshold != nullptr) ? threshold : &depthPreviewThreshold;
+ fillOutputStreams(&depthEntry, outputStreams, depthThreshold,
+ ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_OUTPUT);
}
return Status::OK;
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
index 48816ad9..12a26d2 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -751,8 +751,6 @@
std::vector<AvailableStream>& outputStreams,
const AvailableStream* threshold,
bool maxResolution) {
- AvailableStream depthPreviewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
- static_cast<int32_t>(PixelFormat::Y16)};
if (nullptr == staticMeta) {
return Status::ILLEGAL_ARGUMENT;
}
@@ -778,7 +776,11 @@
}
if (foundDepth == 0 && (0 == (depthEntry.count % 4))) {
- fillOutputStreams(&depthEntry, outputStreams, &depthPreviewThreshold,
+ AvailableStream depthPreviewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
+ static_cast<int32_t>(PixelFormat::Y16)};
+ const AvailableStream* depthThreshold =
+ (threshold != nullptr) ? threshold : &depthPreviewThreshold;
+ fillOutputStreams(&depthEntry, outputStreams, depthThreshold,
ANDROID_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS_OUTPUT);
}
diff --git a/cas/aidl/default/OWNERS b/cas/aidl/OWNERS
similarity index 100%
rename from cas/aidl/default/OWNERS
rename to cas/aidl/OWNERS
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl
index 28c9eb0..903ab92 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ICas.aidl
@@ -36,6 +36,7 @@
@VintfStability
interface ICas {
void closeSession(in byte[] sessionId);
+ byte[] openSessionDefault();
byte[] openSession(in android.hardware.cas.SessionIntent intent, in android.hardware.cas.ScramblingMode mode);
void processEcm(in byte[] sessionId, in byte[] ecm);
void processEmm(in byte[] emm);
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl
index a0b08c9..9d542cc 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/ScramblingMode.aidl
@@ -36,18 +36,18 @@
@Backing(type="int") @VintfStability
enum ScramblingMode {
RESERVED = 0,
- DVB_CSA1 = 1,
- DVB_CSA2 = 2,
- DVB_CSA3_STANDARD = 3,
- DVB_CSA3_MINIMAL = 4,
- DVB_CSA3_ENHANCE = 5,
- DVB_CISSA_V1 = 6,
- DVB_IDSA = 7,
- MULTI2 = 8,
- AES128 = 9,
- AES_ECB = 10,
- AES_SCTE52 = 11,
- TDES_ECB = 12,
- TDES_SCTE52 = 13,
- AES_CBC = 14,
+ DVB_CSA1,
+ DVB_CSA2,
+ DVB_CSA3_STANDARD,
+ DVB_CSA3_MINIMAL,
+ DVB_CSA3_ENHANCE,
+ DVB_CISSA_V1,
+ DVB_IDSA,
+ MULTI2,
+ AES128,
+ AES_ECB,
+ AES_SCTE52,
+ TDES_ECB,
+ TDES_SCTE52,
+ AES_CBC,
}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SessionIntent.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SessionIntent.aidl
index ade3001..00a2fd7 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SessionIntent.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/SessionIntent.aidl
@@ -35,8 +35,8 @@
/* @hide */
@Backing(type="int") @VintfStability
enum SessionIntent {
- LIVE = 0,
- PLAYBACK = 1,
- RECORD = 2,
- TIMESHIFT = 3,
+ LIVE,
+ PLAYBACK,
+ RECORD,
+ TIMESHIFT,
}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl
index 343c810..3691009 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/Status.aidl
@@ -36,25 +36,25 @@
@VintfStability
parcelable Status {
const int OK = 0;
- const int ERROR_CAS_NO_LICENSE = -1;
- const int ERROR_CAS_LICENSE_EXPIRED = -2;
- const int ERROR_CAS_SESSION_NOT_OPENED = -3;
- const int ERROR_CAS_CANNOT_HANDLE = -4;
- const int ERROR_CAS_INVALID_STATE = -5;
- const int BAD_VALUE = -6;
- const int ERROR_CAS_NOT_PROVISIONED = -7;
- const int ERROR_CAS_RESOURCE_BUSY = -8;
- const int ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION = -9;
- const int ERROR_CAS_TAMPER_DETECTED = -10;
- const int ERROR_CAS_DEVICE_REVOKED = -11;
- const int ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED = -12;
- const int ERROR_CAS_DECRYPT = -13;
- const int ERROR_CAS_UNKNOWN = -14;
- const int ERROR_CAS_NEED_ACTIVATION = -15;
- const int ERROR_CAS_NEED_PAIRING = -16;
- const int ERROR_CAS_NO_CARD = -17;
- const int ERROR_CAS_CARD_MUTE = -18;
- const int ERROR_CAS_CARD_INVALID = -19;
- const int ERROR_CAS_BLACKOUT = -20;
- const int ERROR_CAS_REBOOTING = -21;
+ const int ERROR_CAS_NO_LICENSE = 1;
+ const int ERROR_CAS_LICENSE_EXPIRED = 2;
+ const int ERROR_CAS_SESSION_NOT_OPENED = 3;
+ const int ERROR_CAS_CANNOT_HANDLE = 4;
+ const int ERROR_CAS_INVALID_STATE = 5;
+ const int BAD_VALUE = 6;
+ const int ERROR_CAS_NOT_PROVISIONED = 7;
+ const int ERROR_CAS_RESOURCE_BUSY = 8;
+ const int ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION = 9;
+ const int ERROR_CAS_TAMPER_DETECTED = 10;
+ const int ERROR_CAS_DEVICE_REVOKED = 11;
+ const int ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED = 12;
+ const int ERROR_CAS_DECRYPT = 13;
+ const int ERROR_CAS_UNKNOWN = 14;
+ const int ERROR_CAS_NEED_ACTIVATION = 15;
+ const int ERROR_CAS_NEED_PAIRING = 16;
+ const int ERROR_CAS_NO_CARD = 17;
+ const int ERROR_CAS_CARD_MUTE = 18;
+ const int ERROR_CAS_CARD_INVALID = 19;
+ const int ERROR_CAS_BLACKOUT = 20;
+ const int ERROR_CAS_REBOOTING = 21;
}
diff --git a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl
index 165c0d4..0cf37dd 100644
--- a/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl
+++ b/cas/aidl/aidl_api/android.hardware.cas/current/android/hardware/cas/StatusEvent.aidl
@@ -35,6 +35,6 @@
/* @hide */
@Backing(type="byte") @VintfStability
enum StatusEvent {
- PLUGIN_PHYSICAL_MODULE_CHANGED = 0,
- PLUGIN_SESSION_NUMBER_CHANGED = 1,
+ PLUGIN_PHYSICAL_MODULE_CHANGED,
+ PLUGIN_SESSION_NUMBER_CHANGED,
}
diff --git a/cas/aidl/android/hardware/cas/ICas.aidl b/cas/aidl/android/hardware/cas/ICas.aidl
index e6494ae..272cb10 100644
--- a/cas/aidl/android/hardware/cas/ICas.aidl
+++ b/cas/aidl/android/hardware/cas/ICas.aidl
@@ -35,6 +35,14 @@
void closeSession(in byte[] sessionId);
/**
+ * Open a session to descramble one or more streams without specifying intention
+ * and scrambling mode.
+ *
+ * @return sessionId The id of the newly opened session.
+ */
+ byte[] openSessionDefault();
+
+ /**
* Open a session to descramble one or more streams by specifying intention
* and scrambling mode.
*
diff --git a/cas/aidl/android/hardware/cas/Status.aidl b/cas/aidl/android/hardware/cas/Status.aidl
index e7ae8ff..ba0bd65 100644
--- a/cas/aidl/android/hardware/cas/Status.aidl
+++ b/cas/aidl/android/hardware/cas/Status.aidl
@@ -31,50 +31,50 @@
* The CAS plugin must return ERROR_CAS_NO_LICENSE, when descrambling is
* attempted and no license keys have been provided.
*/
- const int ERROR_CAS_NO_LICENSE = -1;
+ const int ERROR_CAS_NO_LICENSE = 1;
/**
* ERROR_CAS_LICENSE_EXPIRED must be returned when an attempt is made
* to use a license and the keys in that license have expired.
*/
- const int ERROR_CAS_LICENSE_EXPIRED = -2;
+ const int ERROR_CAS_LICENSE_EXPIRED = 2;
/**
* The CAS plugin must return ERROR_CAS_SESSION_NOT_OPENED when an
* attempt is made to use a session that has not been opened.
*/
- const int ERROR_CAS_SESSION_NOT_OPENED = -3;
+ const int ERROR_CAS_SESSION_NOT_OPENED = 3;
/**
* The CAS plugin must return ERROR_CAS_CANNOT_HANDLE when an unsupported
* data format or operation is attempted.
*/
- const int ERROR_CAS_CANNOT_HANDLE = -4;
+ const int ERROR_CAS_CANNOT_HANDLE = 4;
/**
* ERROR_CAS_INVALID_STATE must be returned when the device is in a state
* where it is not able to perform descrambling.
*/
- const int ERROR_CAS_INVALID_STATE = -5;
+ const int ERROR_CAS_INVALID_STATE = 5;
/**
* The CAS plugin must return BAD_VALUE whenever an illegal parameter is
* passed to one of the interface functions.
*/
- const int BAD_VALUE = -6;
+ const int BAD_VALUE = 6;
/**
* The CAS plugin must return ERROR_CAS_NOT_PROVISIONED when the device
* has not yet been provisioned.
*/
- const int ERROR_CAS_NOT_PROVISIONED = -7;
+ const int ERROR_CAS_NOT_PROVISIONED = 7;
/**
* ERROR_CAS_RESOURCE_BUSY must be returned when resources, such as CAS
* sessions or secure buffers are not available to perform a requested
* operation because they are already in use.
*/
- const int ERROR_CAS_RESOURCE_BUSY = -8;
+ const int ERROR_CAS_RESOURCE_BUSY = 8;
/**
* The CAS Plugin must return ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION
@@ -82,72 +82,72 @@
* sufficient to meet the requirements in the license policy. HDCP is an
* example of a form of output protection.
*/
- const int ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION = -9;
+ const int ERROR_CAS_INSUFFICIENT_OUTPUT_PROTECTION = 9;
/**
* The CAS Plugin must return ERROR_CAS_TAMPER_DETECTED if an attempt to
* tamper with the CAS system is detected.
*/
- const int ERROR_CAS_TAMPER_DETECTED = -10;
+ const int ERROR_CAS_TAMPER_DETECTED = 10;
/**
* The CAS Plugin must return ERROR_CAS_DEVICE_REVOKED if the response
* indicates that the device has been revoked. Device revocation means
* that the device is no longer permitted to play content.
*/
- const int ERROR_CAS_DEVICE_REVOKED = -11;
+ const int ERROR_CAS_DEVICE_REVOKED = 11;
/**
* The CAS plugin must return ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED when
* descrambling is failing because the session is not initialized properly.
*/
- const int ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED = -12;
+ const int ERROR_CAS_DECRYPT_UNIT_NOT_INITIALIZED = 12;
/**
* The CAS Plugin must return ERROR_CAS_DECRYPT if the DescramblerPlugin's
* descramble operation fails.
*/
- const int ERROR_CAS_DECRYPT = -13;
+ const int ERROR_CAS_DECRYPT = 13;
/**
* ERROR_CAS_UNKNOWN must be returned when a fatal failure occurs and no
* other defined error is appropriate.
*/
- const int ERROR_CAS_UNKNOWN = -14;
+ const int ERROR_CAS_UNKNOWN = 14;
/**
* ERROR_CAS_NEED_ACTIVATION is used to trigger device activation process.
*/
- const int ERROR_CAS_NEED_ACTIVATION = -15;
+ const int ERROR_CAS_NEED_ACTIVATION = 15;
/**
* ERROR_CAS_NEED_PAIRING is used to trigger pairing process.
*/
- const int ERROR_CAS_NEED_PAIRING = -16;
+ const int ERROR_CAS_NEED_PAIRING = 16;
/**
* ERROR_CAS_NO_CARD is used to report no smart card for descrambling.
*/
- const int ERROR_CAS_NO_CARD = -17;
+ const int ERROR_CAS_NO_CARD = 17;
/**
* ERROR_CAS_CARD_MUTE is used to report smart card is muted for
* descrambling.
*/
- const int ERROR_CAS_CARD_MUTE = -18;
+ const int ERROR_CAS_CARD_MUTE = 18;
/**
* ERROR_CAS_CARD_INVALID is used to report smart card isn't valid.
*/
- const int ERROR_CAS_CARD_INVALID = -19;
+ const int ERROR_CAS_CARD_INVALID = 19;
/**
* ERROR_CAS_BLACKOUT is used to report geographical blackout.
*/
- const int ERROR_CAS_BLACKOUT = -20;
+ const int ERROR_CAS_BLACKOUT = 20;
/**
* ERROR_CAS_REBOOTING is used to report CAS is during rebooting.
*/
- const int ERROR_CAS_REBOOTING = -21;
+ const int ERROR_CAS_REBOOTING = 21;
}
diff --git a/cas/aidl/default/CasImpl.cpp b/cas/aidl/default/CasImpl.cpp
index 2d31b35..f08fcc0 100755
--- a/cas/aidl/default/CasImpl.cpp
+++ b/cas/aidl/default/CasImpl.cpp
@@ -128,6 +128,19 @@
return toStatus(holder->setPrivateData(pvtData));
}
+ScopedAStatus CasImpl::openSessionDefault(vector<uint8_t>* sessionId) {
+ ALOGV("%s", __FUNCTION__);
+
+ shared_ptr<CasPlugin> holder = atomic_load(&mPluginHolder);
+ status_t err = INVALID_OPERATION;
+ if (holder.get() != nullptr) {
+ err = holder->openSession(sessionId);
+ holder.reset();
+ }
+
+ return toStatus(err);
+}
+
ScopedAStatus CasImpl::openSession(SessionIntent intent, ScramblingMode mode,
vector<uint8_t>* sessionId) {
ALOGV("%s", __FUNCTION__);
diff --git a/cas/aidl/default/CasImpl.h b/cas/aidl/default/CasImpl.h
index 84a8115..2488a7f 100755
--- a/cas/aidl/default/CasImpl.h
+++ b/cas/aidl/default/CasImpl.h
@@ -53,6 +53,8 @@
virtual ScopedAStatus setPrivateData(const vector<uint8_t>& pvtData) override;
+ virtual ScopedAStatus openSessionDefault(vector<uint8_t>* sessionId) override;
+
virtual ScopedAStatus openSession(SessionIntent intent, ScramblingMode mode,
vector<uint8_t>* sessionId) override;
diff --git a/cas/aidl/vts/functional/VtsHalCasAidlTargetTest.cpp b/cas/aidl/vts/functional/VtsHalCasAidlTargetTest.cpp
index 266b55d..4c904a8 100644
--- a/cas/aidl/vts/functional/VtsHalCasAidlTargetTest.cpp
+++ b/cas/aidl/vts/functional/VtsHalCasAidlTargetTest.cpp
@@ -286,6 +286,7 @@
} OobInputTestParams;
AssertionResult createCasPlugin(int32_t caSystemId);
+ AssertionResult openCasSessionDefault(vector<uint8_t>* sessionId);
AssertionResult openCasSession(vector<uint8_t>* sessionId, SessionIntent intent,
ScramblingMode mode);
AssertionResult descrambleTestInputBuffer(const shared_ptr<IDescrambler>& descrambler,
@@ -331,6 +332,10 @@
return AssertionResult(mDescrambler != nullptr);
}
+AssertionResult MediaCasAidlTest::openCasSessionDefault(vector<uint8_t>* sessionId) {
+ return AssertionResult(mMediaCas->openSessionDefault(sessionId).isOk());
+}
+
AssertionResult MediaCasAidlTest::openCasSession(vector<uint8_t>* sessionId, SessionIntent intent,
ScramblingMode mode) {
return AssertionResult(mMediaCas->openSession(intent, mode, sessionId).isOk());
@@ -485,6 +490,32 @@
ADD_FAILURE() << "ClearKey plugin not installed";
}
+TEST_P(MediaCasAidlTest, TestClearKeyDefaultSessionClosedAfterRelease) {
+ description("Test that all sessions are closed after a MediaCas object is released");
+
+ ASSERT_TRUE(createCasPlugin(CLEAR_KEY_SYSTEM_ID));
+
+ EXPECT_TRUE(mMediaCas->provision(PROVISION_STR).isOk());
+
+ vector<uint8_t> sessionId;
+ ASSERT_TRUE(openCasSessionDefault(&sessionId));
+
+ vector<uint8_t> streamSessionId;
+ ASSERT_TRUE(openCasSessionDefault(&streamSessionId));
+
+ EXPECT_TRUE(mMediaCas->release().isOk());
+
+ if (mDescrambler != nullptr) {
+ auto status = mDescrambler->setMediaCasSession(sessionId);
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, status.getServiceSpecificError());
+
+ status = mDescrambler->setMediaCasSession(streamSessionId);
+ EXPECT_FALSE(status.isOk());
+ EXPECT_EQ(Status::ERROR_CAS_SESSION_NOT_OPENED, status.getServiceSpecificError());
+ }
+}
+
TEST_P(MediaCasAidlTest, TestClearKeySessionClosedAfterRelease) {
description("Test that all sessions are closed after a MediaCas object is released");
diff --git a/compatibility_matrices/compatibility_matrix.8.xml b/compatibility_matrices/compatibility_matrix.8.xml
index c17cb15..eb649bf 100644
--- a/compatibility_matrices/compatibility_matrix.8.xml
+++ b/compatibility_matrices/compatibility_matrix.8.xml
@@ -756,14 +756,6 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="hidl" optional="true">
- <name>android.hardware.usb.gadget</name>
- <version>1.0-2</version>
- <interface>
- <name>IUsbGadget</name>
- <instance>default</instance>
- </interface>
- </hal>
<hal format="aidl" optional="true">
<name>android.hardware.usb.gadget</name>
<interface>
diff --git a/health/aidl/OWNERS b/health/aidl/OWNERS
index fcad499..9bbcef8 100644
--- a/health/aidl/OWNERS
+++ b/health/aidl/OWNERS
@@ -1,4 +1,4 @@
# Bug component: 30545
elsk@google.com
smoreland@google.com
-stayfan@google.com
+wjack@google.com
diff --git a/neuralnetworks/1.2/utils/src/BurstUtils.cpp b/neuralnetworks/1.2/utils/src/BurstUtils.cpp
index b589c46..c4c096d 100644
--- a/neuralnetworks/1.2/utils/src/BurstUtils.cpp
+++ b/neuralnetworks/1.2/utils/src/BurstUtils.cpp
@@ -190,12 +190,13 @@
size_t index = 0;
// validate packet information
- if (data.size() == 0 || data[index].getDiscriminator() != discriminator::packetInformation) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::packetInformation) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage packet information
- const FmqRequestDatum::PacketInformation& packetInfo = data[index].packetInformation();
+ const FmqRequestDatum::PacketInformation& packetInfo = data.at(index).packetInformation();
index++;
const uint32_t packetSize = packetInfo.packetSize;
const uint32_t numberOfInputOperands = packetInfo.numberOfInputOperands;
@@ -212,13 +213,14 @@
inputs.reserve(numberOfInputOperands);
for (size_t operand = 0; operand < numberOfInputOperands; ++operand) {
// validate input operand information
- if (data[index].getDiscriminator() != discriminator::inputOperandInformation) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::inputOperandInformation) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage operand information
const FmqRequestDatum::OperandInformation& operandInfo =
- data[index].inputOperandInformation();
+ data.at(index).inputOperandInformation();
index++;
const bool hasNoValue = operandInfo.hasNoValue;
const V1_0::DataLocation location = operandInfo.location;
@@ -229,12 +231,13 @@
dimensions.reserve(numberOfDimensions);
for (size_t i = 0; i < numberOfDimensions; ++i) {
// validate dimension
- if (data[index].getDiscriminator() != discriminator::inputOperandDimensionValue) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::inputOperandDimensionValue) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage dimension
- const uint32_t dimension = data[index].inputOperandDimensionValue();
+ const uint32_t dimension = data.at(index).inputOperandDimensionValue();
index++;
// store result
@@ -251,13 +254,14 @@
outputs.reserve(numberOfOutputOperands);
for (size_t operand = 0; operand < numberOfOutputOperands; ++operand) {
// validate output operand information
- if (data[index].getDiscriminator() != discriminator::outputOperandInformation) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::outputOperandInformation) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage operand information
const FmqRequestDatum::OperandInformation& operandInfo =
- data[index].outputOperandInformation();
+ data.at(index).outputOperandInformation();
index++;
const bool hasNoValue = operandInfo.hasNoValue;
const V1_0::DataLocation location = operandInfo.location;
@@ -268,12 +272,13 @@
dimensions.reserve(numberOfDimensions);
for (size_t i = 0; i < numberOfDimensions; ++i) {
// validate dimension
- if (data[index].getDiscriminator() != discriminator::outputOperandDimensionValue) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::outputOperandDimensionValue) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage dimension
- const uint32_t dimension = data[index].outputOperandDimensionValue();
+ const uint32_t dimension = data.at(index).outputOperandDimensionValue();
index++;
// store result
@@ -290,12 +295,13 @@
slots.reserve(numberOfPools);
for (size_t pool = 0; pool < numberOfPools; ++pool) {
// validate input operand information
- if (data[index].getDiscriminator() != discriminator::poolIdentifier) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::poolIdentifier) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage operand information
- const int32_t poolId = data[index].poolIdentifier();
+ const int32_t poolId = data.at(index).poolIdentifier();
index++;
// store result
@@ -303,17 +309,17 @@
}
// validate measureTiming
- if (data[index].getDiscriminator() != discriminator::measureTiming) {
+ if (index >= data.size() || data.at(index).getDiscriminator() != discriminator::measureTiming) {
return NN_ERROR() << "FMQ Request packet ill-formed";
}
// unpackage measureTiming
- const V1_2::MeasureTiming measure = data[index].measureTiming();
+ const V1_2::MeasureTiming measure = data.at(index).measureTiming();
index++;
// validate packet information
if (index != packetSize) {
- return NN_ERROR() << "FMQ Result packet ill-formed";
+ return NN_ERROR() << "FMQ Request packet ill-formed";
}
// return request
@@ -328,12 +334,13 @@
size_t index = 0;
// validate packet information
- if (data.size() == 0 || data[index].getDiscriminator() != discriminator::packetInformation) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::packetInformation) {
return NN_ERROR() << "FMQ Result packet ill-formed";
}
// unpackage packet information
- const FmqResultDatum::PacketInformation& packetInfo = data[index].packetInformation();
+ const FmqResultDatum::PacketInformation& packetInfo = data.at(index).packetInformation();
index++;
const uint32_t packetSize = packetInfo.packetSize;
const V1_0::ErrorStatus errorStatus = packetInfo.errorStatus;
@@ -349,12 +356,13 @@
outputShapes.reserve(numberOfOperands);
for (size_t operand = 0; operand < numberOfOperands; ++operand) {
// validate operand information
- if (data[index].getDiscriminator() != discriminator::operandInformation) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::operandInformation) {
return NN_ERROR() << "FMQ Result packet ill-formed";
}
// unpackage operand information
- const FmqResultDatum::OperandInformation& operandInfo = data[index].operandInformation();
+ const FmqResultDatum::OperandInformation& operandInfo = data.at(index).operandInformation();
index++;
const bool isSufficient = operandInfo.isSufficient;
const uint32_t numberOfDimensions = operandInfo.numberOfDimensions;
@@ -364,12 +372,13 @@
dimensions.reserve(numberOfDimensions);
for (size_t i = 0; i < numberOfDimensions; ++i) {
// validate dimension
- if (data[index].getDiscriminator() != discriminator::operandDimensionValue) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::operandDimensionValue) {
return NN_ERROR() << "FMQ Result packet ill-formed";
}
// unpackage dimension
- const uint32_t dimension = data[index].operandDimensionValue();
+ const uint32_t dimension = data.at(index).operandDimensionValue();
index++;
// store result
@@ -381,12 +390,13 @@
}
// validate execution timing
- if (data[index].getDiscriminator() != discriminator::executionTiming) {
+ if (index >= data.size() ||
+ data.at(index).getDiscriminator() != discriminator::executionTiming) {
return NN_ERROR() << "FMQ Result packet ill-formed";
}
// unpackage execution timing
- const V1_2::Timing timing = data[index].executionTiming();
+ const V1_2::Timing timing = data.at(index).executionTiming();
index++;
// validate packet information
diff --git a/radio/1.4/vts/functional/radio_hidl_hal_api.cpp b/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
index b0b984c..8f357a0 100644
--- a/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
@@ -232,7 +232,8 @@
EXPECT_EQ(serial, radioRsp_v1_4->rspInfo.serial);
ALOGI("setPreferredNetworkTypeBitmap, rspInfo.error = %s\n",
toString(radioRsp_v1_4->rspInfo.error).c_str());
- EXPECT_EQ(RadioError::NONE, radioRsp_v1_4->rspInfo.error);
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+ {RadioError::NONE, RadioError::MODE_NOT_SUPPORTED}));
if (radioRsp_v1_4->rspInfo.error == RadioError::NONE) {
// give some time for modem to set the value.
sleep(3);
diff --git a/secure_element/1.0/vts/OWNERS b/secure_element/1.0/vts/OWNERS
deleted file mode 100644
index c7963e7..0000000
--- a/secure_element/1.0/vts/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-alisher@google.com
-jackcwyu@google.com
-georgekgchang@google.com
-zachoverflow@google.com
diff --git a/secure_element/1.0/vts/functional/OWNERS b/secure_element/1.0/vts/functional/OWNERS
deleted file mode 100644
index a7ee7e9..0000000
--- a/secure_element/1.0/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 456592
-jackcwyu@google.com
diff --git a/secure_element/1.1/vts/OWNERS b/secure_element/1.1/vts/OWNERS
deleted file mode 100644
index c7963e7..0000000
--- a/secure_element/1.1/vts/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-alisher@google.com
-jackcwyu@google.com
-georgekgchang@google.com
-zachoverflow@google.com
diff --git a/secure_element/1.1/vts/functional/OWNERS b/secure_element/1.1/vts/functional/OWNERS
deleted file mode 100644
index a7ee7e9..0000000
--- a/secure_element/1.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 456592
-jackcwyu@google.com
diff --git a/secure_element/1.2/vts/OWNERS b/secure_element/1.2/vts/OWNERS
deleted file mode 100644
index c7963e7..0000000
--- a/secure_element/1.2/vts/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-alisher@google.com
-jackcwyu@google.com
-georgekgchang@google.com
-zachoverflow@google.com
diff --git a/secure_element/1.2/vts/functional/OWNERS b/secure_element/1.2/vts/functional/OWNERS
deleted file mode 100644
index a7ee7e9..0000000
--- a/secure_element/1.2/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 456592
-jackcwyu@google.com
diff --git a/secure_element/OWNERS b/secure_element/OWNERS
new file mode 100644
index 0000000..492696b
--- /dev/null
+++ b/secure_element/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 456592
+alisher@google.com
+jackcwyu@google.com
+georgekgchang@google.com
+henrichataing@google.com
diff --git a/secure_element/aidl/default/main.cpp b/secure_element/aidl/default/main.cpp
index 6149eae..0822402 100644
--- a/secure_element/aidl/default/main.cpp
+++ b/secure_element/aidl/default/main.cpp
@@ -586,7 +586,7 @@
// The selected basic or logical channel is not opened.
if (channel_number >= channels_.size() || !channels_[channel_number].opened) {
- return ScopedAStatus::ok();
+ return ScopedAStatus::fromServiceSpecificError(FAILED);
}
// TODO(b/123254068) - this is not an implementation of the OMAPI protocol
diff --git a/secure_element/aidl/vts/VtsHalSecureElementTargetTest.cpp b/secure_element/aidl/vts/VtsHalSecureElementTargetTest.cpp
index c265579..37ff1b2 100644
--- a/secure_element/aidl/vts/VtsHalSecureElementTargetTest.cpp
+++ b/secure_element/aidl/vts/VtsHalSecureElementTargetTest.cpp
@@ -109,6 +109,7 @@
}
void TearDown() override {
+ EXPECT_OK(secure_element_->reset());
secure_element_ = nullptr;
secure_element_callback_ = nullptr;
}
@@ -232,10 +233,10 @@
std::vector<uint8_t> basic_channel_response;
LogicalChannelResponse logical_channel_response;
- // closeChannel called on non-existing basic or logical channel is a no-op
- // and shall succeed.
- EXPECT_OK(secure_element_->closeChannel(0));
- EXPECT_OK(secure_element_->closeChannel(1));
+ // closeChannel called on non-existing basic or logical channel
+ // shall fail.
+ EXPECT_ERR(secure_element_->closeChannel(0));
+ EXPECT_ERR(secure_element_->closeChannel(1));
// closeChannel called on basic channel closes the basic channel.
EXPECT_OK(secure_element_->openBasicChannel(kSelectableAid, 0x00, &basic_channel_response));
diff --git a/security/dice/aidl/default/service.rs b/security/dice/aidl/default/service.rs
index eebf333..0197f2c 100644
--- a/security/dice/aidl/default/service.rs
+++ b/security/dice/aidl/default/service.rs
@@ -21,7 +21,6 @@
};
use diced_sample_inputs::make_sample_bcc_and_cdis;
use serde::{Deserialize, Serialize};
-use std::convert::TryInto;
use std::panic;
use std::sync::Arc;
@@ -76,7 +75,7 @@
// Saying hi.
log::info!("android.hardware.security.dice is starting.");
- let (cdi_attest, cdi_seal, bcc) =
+ let dice_artifacts =
make_sample_bcc_and_cdis().expect("Failed to construct sample dice chain.");
let hal_impl = Arc::new(
@@ -85,13 +84,9 @@
// This service does not start a thread pool. The main thread is the only thread
// joining the thread pool, thereby keeping the process single threaded.
ResidentHal::new(InsecureSerializableArtifacts {
- cdi_attest: cdi_attest[..]
- .try_into()
- .expect("Failed to convert cdi_attest to array reference."),
- cdi_seal: cdi_seal[..]
- .try_into()
- .expect("Failed to convert cdi_seal to array reference."),
- bcc,
+ cdi_attest: dice_artifacts.cdi_values.cdi_attest,
+ cdi_seal: dice_artifacts.cdi_values.cdi_seal,
+ bcc: dice_artifacts.bcc[..].to_vec(),
})
}
.expect("Failed to create ResidentHal implementation."),
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index 99d2510..e46aeee 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -86,7 +86,17 @@
} // namespace
class AttestKeyTest : public KeyMintAidlTestBase {
+ public:
+ void SetUp() override {
+ check_skip_test();
+ KeyMintAidlTestBase::SetUp();
+ }
+
protected:
+ const string FEATURE_KEYSTORE_APP_ATTEST_KEY = "android.hardware.keystore.app_attest_key";
+
+ const string FEATURE_STRONGBOX_KEYSTORE = "android.hardware.strongbox_keystore";
+
ErrorCode GenerateAttestKey(const AuthorizationSet& key_desc,
const optional<AttestationKey>& attest_key,
vector<uint8_t>* key_blob,
@@ -111,6 +121,59 @@
}
return GenerateKey(key_desc, attest_key, key_blob, key_characteristics, cert_chain);
}
+
+ // Check if ATTEST_KEY feature is disabled
+ bool is_attest_key_feature_disabled(void) const {
+ if (!check_feature(FEATURE_KEYSTORE_APP_ATTEST_KEY)) {
+ GTEST_LOG_(INFO) << "Feature " + FEATURE_KEYSTORE_APP_ATTEST_KEY + " is disabled";
+ return true;
+ }
+
+ return false;
+ }
+
+ // Check if StrongBox KeyStore is enabled
+ bool is_strongbox_enabled(void) const {
+ if (check_feature(FEATURE_STRONGBOX_KEYSTORE)) {
+ GTEST_LOG_(INFO) << "Feature " + FEATURE_STRONGBOX_KEYSTORE + " is enabled";
+ return true;
+ }
+
+ return false;
+ }
+
+ // Check if chipset has received a waiver allowing it to be launched with
+ // Android S (or later) with Keymaster 4.0 in StrongBox
+ bool is_chipset_allowed_km4_strongbox(void) const {
+ std::array<char, PROPERTY_VALUE_MAX> buffer;
+
+ auto res = property_get("ro.vendor.qti.soc_model", buffer.data(), nullptr);
+ if (res <= 0) return false;
+
+ const string allowed_soc_models[] = {"SM8450", "SM8475", "SM8550", "SXR2230P"};
+
+ for (const string model : allowed_soc_models) {
+ if (model.compare(buffer.data()) == 0) {
+ GTEST_LOG_(INFO) << "QTI SOC Model " + model + " is allowed SB KM 4.0";
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ // Skip the test if all the following conditions hold:
+ // 1. ATTEST_KEY feature is disabled
+ // 2. STRONGBOX is enabled
+ // 3. The device is running one of the chipsets that have received a waiver
+ // allowing it to be launched with Android S (or later) with Keymaster 4.0
+ // in StrongBox
+ void check_skip_test(void) const {
+ if (is_attest_key_feature_disabled() && is_strongbox_enabled() &&
+ is_chipset_allowed_km4_strongbox()) {
+ GTEST_SKIP() << "Test is not applicable";
+ }
+ }
};
/*
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index e9cbe10..588a1d4 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -2052,9 +2052,10 @@
// Check whether the given named feature is available.
bool check_feature(const std::string& name) {
::android::sp<::android::IServiceManager> sm(::android::defaultServiceManager());
- ::android::sp<::android::IBinder> binder(sm->getService(::android::String16("package_native")));
+ ::android::sp<::android::IBinder> binder(
+ sm->waitForService(::android::String16("package_native")));
if (binder == nullptr) {
- GTEST_LOG_(ERROR) << "getService package_native failed";
+ GTEST_LOG_(ERROR) << "waitForService package_native failed";
return false;
}
::android::sp<::android::content::pm::IPackageManagerNative> packageMgr =
diff --git a/staging/threadnetwork/OWNERS b/staging/threadnetwork/OWNERS
new file mode 100644
index 0000000..037215d
--- /dev/null
+++ b/staging/threadnetwork/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 1203089
+
+wgtdkp@google.com
+xyk@google.com
+zhanglongxia@google.com
diff --git a/staging/threadnetwork/README.md b/staging/threadnetwork/README.md
new file mode 100644
index 0000000..12104e5
--- /dev/null
+++ b/staging/threadnetwork/README.md
@@ -0,0 +1,12 @@
+# Staging threadnetwork HAL interface
+
+The directory includes the unstable/unreleased version of `hardware/interfaces/threadnetwork`
+code which should **NOT** be used in production. But vendors may start verifying their hardware
+with the HAL interface.
+
+This directory will be cleaned up when the stable Thread HAL interface is added in
+`hardware/interfaces/threadnetwork` by version `V` or later.
+
+More information about _Thread_:
+- https://www.threadgroup.org
+- https://openthread.io
diff --git a/tetheroffload/aidl/android/hardware/tetheroffload/IOffload.aidl b/tetheroffload/aidl/android/hardware/tetheroffload/IOffload.aidl
index 30b2c8d..984f2a5 100644
--- a/tetheroffload/aidl/android/hardware/tetheroffload/IOffload.aidl
+++ b/tetheroffload/aidl/android/hardware/tetheroffload/IOffload.aidl
@@ -32,8 +32,7 @@
/**
* Indicates intent to start offload for tethering in immediate future.
*
- * This API must be called exactly once the first time that Tethering is requested by
- * the user.
+ * This API must be called exactly once when Tethering is requested by the user.
*
* If this API is called multiple times without first calling stopOffload, then the subsequent
* calls must fail without changing the state of the server.
@@ -168,7 +167,6 @@
* or negative number of bytes).
* - EX_ILLEGAL_STATE if this method is called before initOffload(), or if this method
* is called after stopOffload().
- * - EX_UNSUPPORTED_OPERATION if it is not supported.
* - EX_SERVICE_SPECIFIC with the error message set to a human-readable reason for the
* error.
*/
@@ -269,7 +267,7 @@
* This API may only be called after initOffload and before stopOffload.
*
* @param iface Downstream interface
- * @param prefix Downstream prefix depicting address that must no longer be offloaded
+ * @param prefix Downstream prefix depicting prefix that must no longer be offloaded
* For e.g. 192.168.1.0/24 or 2001:4860:684::/64)
*
* @throws:
diff --git a/tetheroffload/aidl/android/hardware/tetheroffload/OffloadCallbackEvent.aidl b/tetheroffload/aidl/android/hardware/tetheroffload/OffloadCallbackEvent.aidl
index a95f674..15a1f93 100644
--- a/tetheroffload/aidl/android/hardware/tetheroffload/OffloadCallbackEvent.aidl
+++ b/tetheroffload/aidl/android/hardware/tetheroffload/OffloadCallbackEvent.aidl
@@ -55,7 +55,7 @@
*/
OFFLOAD_STOPPED_LIMIT_REACHED = 5,
/**
- * This event is fired when the quota, applied in setDataWarning, has expired. It is
+ * This event is fired when the quota, applied in setDataWarningAndLimit, has expired. It is
* recommended that the client query for statistics immediately after receiving this event.
* Any offloaded traffic will continue to be offloaded until offload is stopped or
* OFFLOAD_STOPPED_LIMIT_REACHED is sent.
diff --git a/tetheroffload/aidl/vts/functional/VtsHalTetheroffloadTargetTest.cpp b/tetheroffload/aidl/vts/functional/VtsHalTetheroffloadTargetTest.cpp
index fc8abbd..f46c9ab 100644
--- a/tetheroffload/aidl/vts/functional/VtsHalTetheroffloadTargetTest.cpp
+++ b/tetheroffload/aidl/vts/functional/VtsHalTetheroffloadTargetTest.cpp
@@ -152,15 +152,13 @@
void initOffload(const bool expectedResult) {
unique_fd ufd1(netlinkSocket(kFd1Groups));
if (ufd1.get() < 0) {
- ALOGE("Unable to create conntrack sockets: %d/%s", errno, strerror(errno));
- FAIL();
+ FAIL() << "Unable to create conntrack sockets: " << strerror(errno);
}
ndk::ScopedFileDescriptor fd1 = ndk::ScopedFileDescriptor(ufd1.release());
unique_fd ufd2(netlinkSocket(kFd2Groups));
if (ufd2.get() < 0) {
- ALOGE("Unable to create conntrack sockets: %d/%s", errno, strerror(errno));
- FAIL();
+ FAIL() << "Unable to create conntrack sockets: " << strerror(errno);
}
ndk::ScopedFileDescriptor fd2 = ndk::ScopedFileDescriptor(ufd2.release());
@@ -214,8 +212,7 @@
ndk::ScopedFileDescriptor fd1 = ndk::ScopedFileDescriptor(-1);
unique_fd ufd2(netlinkSocket(kFd2Groups));
if (ufd2.get() < 0) {
- ALOGE("Unable to create conntrack sockets: %d/%s", errno, strerror(errno));
- FAIL();
+ FAIL() << "Unable to create conntrack sockets: " << strerror(errno);
}
ndk::ScopedFileDescriptor fd2 = ndk::ScopedFileDescriptor(ufd2.release());
mTetheringOffloadCallback = ndk::SharedRefBase::make<TetheringOffloadCallback>();
@@ -229,8 +226,7 @@
TEST_P(TetheroffloadAidlPreInitTest, TestInitOffloadInvalidFd2ReturnsError) {
unique_fd ufd1(netlinkSocket(kFd1Groups));
if (ufd1.get() < 0) {
- ALOGE("Unable to create conntrack sockets: %d/%s", errno, strerror(errno));
- FAIL();
+ FAIL() << "Unable to create conntrack sockets: " << strerror(errno);
}
ndk::ScopedFileDescriptor fd1 = ndk::ScopedFileDescriptor(ufd1.release());
ndk::ScopedFileDescriptor fd2 = ndk::ScopedFileDescriptor(-1);
@@ -264,7 +260,8 @@
const std::string v4Addr("192.0.0.2");
const std::string v4Gw("192.0.0.1");
const std::vector<std::string> v6Gws{std::string("fe80::db8:1"), std::string("fe80::db8:2")};
- EXPECT_TRUE(mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws).isOk());
+ auto ret = mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws);
+ EXPECT_TRUE(ret.isOk()) << ret;
if (!interfaceIsUp(TEST_IFACE)) {
return;
}
@@ -279,7 +276,7 @@
// Check that calling setLocalPrefixes() without first having called initOffload() returns error.
TEST_P(TetheroffloadAidlPreInitTest, SetLocalPrefixesWithoutInitReturnsError) {
const std::vector<std::string> prefixes{std::string("2001:db8::/64")};
- EXPECT_EQ(mOffload->setLocalPrefixes(prefixes).getExceptionCode(), EX_ILLEGAL_STATE);
+ EXPECT_EQ(EX_ILLEGAL_STATE, mOffload->setLocalPrefixes(prefixes).getExceptionCode());
}
// Check that calling getForwardedStats() without first having called initOffload()
@@ -287,9 +284,10 @@
TEST_P(TetheroffloadAidlPreInitTest, GetForwardedStatsWithoutInitReturnsZeroValues) {
const std::string upstream(TEST_IFACE);
ForwardedStats stats;
- EXPECT_TRUE(mOffload->getForwardedStats(upstream, &stats).isOk());
- EXPECT_EQ(stats.rxBytes, 0ULL);
- EXPECT_EQ(stats.txBytes, 0ULL);
+ auto ret = mOffload->getForwardedStats(upstream, &stats);
+ EXPECT_TRUE(ret.isOk()) << ret;
+ EXPECT_EQ(0ULL, stats.rxBytes);
+ EXPECT_EQ(0ULL, stats.txBytes);
}
// Check that calling setDataWarningAndLimit() without first having called initOffload() returns
@@ -298,8 +296,8 @@
const std::string upstream(TEST_IFACE);
const int64_t warning = 5000LL;
const int64_t limit = 5000LL;
- EXPECT_EQ(mOffload->setDataWarningAndLimit(upstream, warning, limit).getExceptionCode(),
- EX_ILLEGAL_STATE);
+ EXPECT_EQ(EX_ILLEGAL_STATE,
+ mOffload->setDataWarningAndLimit(upstream, warning, limit).getExceptionCode());
}
// Check that calling setUpstreamParameters() without first having called initOffload()
@@ -309,8 +307,8 @@
const std::string v4Addr("192.0.2.0/24");
const std::string v4Gw("192.0.2.1");
const std::vector<std::string> v6Gws{std::string("fe80::db8:1")};
- EXPECT_EQ(mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws).getExceptionCode(),
- EX_ILLEGAL_STATE);
+ EXPECT_EQ(EX_ILLEGAL_STATE,
+ mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws).getExceptionCode());
}
// Check that calling addDownstream() with an IPv4 prefix without first having called
@@ -318,7 +316,7 @@
TEST_P(TetheroffloadAidlPreInitTest, AddIPv4DownstreamWithoutInitReturnsError) {
const std::string iface(TEST_IFACE);
const std::string prefix("192.0.2.0/24");
- EXPECT_EQ(mOffload->addDownstream(iface, prefix).getExceptionCode(), EX_ILLEGAL_STATE);
+ EXPECT_EQ(EX_ILLEGAL_STATE, mOffload->addDownstream(iface, prefix).getExceptionCode());
}
// Check that calling addDownstream() with an IPv6 prefix without first having called
@@ -326,7 +324,7 @@
TEST_P(TetheroffloadAidlPreInitTest, AddIPv6DownstreamWithoutInitReturnsError) {
const std::string iface(TEST_IFACE);
const std::string prefix("2001:db8::/64");
- EXPECT_EQ(mOffload->addDownstream(iface, prefix).getExceptionCode(), EX_ILLEGAL_STATE);
+ EXPECT_EQ(EX_ILLEGAL_STATE, mOffload->addDownstream(iface, prefix).getExceptionCode());
}
// Check that calling removeDownstream() with an IPv4 prefix without first having called
@@ -334,7 +332,7 @@
TEST_P(TetheroffloadAidlPreInitTest, RemoveIPv4DownstreamWithoutInitReturnsError) {
const std::string iface(TEST_IFACE);
const std::string prefix("192.0.2.0/24");
- EXPECT_EQ(mOffload->removeDownstream(iface, prefix).getExceptionCode(), EX_ILLEGAL_STATE);
+ EXPECT_EQ(EX_ILLEGAL_STATE, mOffload->removeDownstream(iface, prefix).getExceptionCode());
}
// Check that calling removeDownstream() with an IPv6 prefix without first having called
@@ -342,7 +340,7 @@
TEST_P(TetheroffloadAidlPreInitTest, RemoveIPv6DownstreamWithoutInitReturnsError) {
const std::string iface(TEST_IFACE);
const std::string prefix("2001:db8::/64");
- EXPECT_EQ(mOffload->removeDownstream(iface, prefix).getExceptionCode(), EX_ILLEGAL_STATE);
+ EXPECT_EQ(EX_ILLEGAL_STATE, mOffload->removeDownstream(iface, prefix).getExceptionCode());
}
/*
@@ -352,19 +350,20 @@
// Test setLocalPrefixes() rejects an IPv4 address.
TEST_P(TetheroffloadAidlGeneralTest, SetLocalPrefixesIPv4AddressFails) {
const std::vector<std::string> prefixes{std::string("192.0.2.1")};
- EXPECT_EQ(mOffload->setLocalPrefixes(prefixes).getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT, mOffload->setLocalPrefixes(prefixes).getExceptionCode());
}
// Test setLocalPrefixes() rejects an IPv6 address.
TEST_P(TetheroffloadAidlGeneralTest, SetLocalPrefixesIPv6AddressFails) {
const std::vector<std::string> prefixes{std::string("fe80::1")};
- EXPECT_EQ(mOffload->setLocalPrefixes(prefixes).getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT, mOffload->setLocalPrefixes(prefixes).getExceptionCode());
}
// Test setLocalPrefixes() accepts both IPv4 and IPv6 prefixes.
TEST_P(TetheroffloadAidlGeneralTest, SetLocalPrefixesIPv4v6PrefixesOk) {
const std::vector<std::string> prefixes{std::string("192.0.2.0/24"), std::string("fe80::/64")};
- EXPECT_TRUE(mOffload->setLocalPrefixes(prefixes).isOk());
+ auto ret = mOffload->setLocalPrefixes(prefixes);
+ EXPECT_TRUE(ret.isOk()) << ret;
}
// Test that setLocalPrefixes() fails given empty input. There is always
@@ -372,13 +371,13 @@
// we still apply {127.0.0.0/8, ::1/128, fe80::/64} here.
TEST_P(TetheroffloadAidlGeneralTest, SetLocalPrefixesEmptyFails) {
const std::vector<std::string> prefixes{};
- EXPECT_EQ(mOffload->setLocalPrefixes(prefixes).getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT, mOffload->setLocalPrefixes(prefixes).getExceptionCode());
}
// Test setLocalPrefixes() fails on incorrectly formed input strings.
TEST_P(TetheroffloadAidlGeneralTest, SetLocalPrefixesInvalidFails) {
const std::vector<std::string> prefixes{std::string("192.0.2.0/24"), std::string("invalid")};
- EXPECT_EQ(mOffload->setLocalPrefixes(prefixes).getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT, mOffload->setLocalPrefixes(prefixes).getExceptionCode());
}
/*
@@ -389,9 +388,10 @@
TEST_P(TetheroffloadAidlGeneralTest, GetForwardedStatsInvalidUpstreamIface) {
const std::string upstream("invalid");
ForwardedStats stats;
- EXPECT_TRUE(mOffload->getForwardedStats(upstream, &stats).isOk());
- EXPECT_EQ(stats.rxBytes, 0ULL);
- EXPECT_EQ(stats.txBytes, 0ULL);
+ auto ret = mOffload->getForwardedStats(upstream, &stats);
+ EXPECT_TRUE(ret.isOk()) << ret;
+ EXPECT_EQ(0ULL, stats.rxBytes);
+ EXPECT_EQ(0ULL, stats.txBytes);
}
// TEST_IFACE is presumed to exist on the device and be up. No packets
@@ -399,9 +399,10 @@
TEST_P(TetheroffloadAidlGeneralTest, GetForwardedStatsDummyIface) {
const std::string upstream(TEST_IFACE);
ForwardedStats stats;
- EXPECT_TRUE(mOffload->getForwardedStats(upstream, &stats).isOk());
- EXPECT_EQ(stats.rxBytes, 0ULL);
- EXPECT_EQ(stats.txBytes, 0ULL);
+ auto ret = mOffload->getForwardedStats(upstream, &stats);
+ EXPECT_TRUE(ret.isOk()) << ret;
+ EXPECT_EQ(0ULL, stats.rxBytes);
+ EXPECT_EQ(0ULL, stats.txBytes);
}
/*
@@ -413,8 +414,8 @@
const std::string upstream("");
const int64_t warning = 12345LL;
const int64_t limit = 67890LL;
- EXPECT_THAT(mOffload->setDataWarningAndLimit(upstream, warning, limit).getExceptionCode(),
- AnyOf(Eq(EX_ILLEGAL_ARGUMENT), Eq(EX_UNSUPPORTED_OPERATION)));
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT,
+ mOffload->setDataWarningAndLimit(upstream, warning, limit).getExceptionCode());
}
// TEST_IFACE is presumed to exist on the device and be up. No packets
@@ -423,8 +424,8 @@
const std::string upstream(TEST_IFACE);
const int64_t warning = 4000LL;
const int64_t limit = 5000LL;
- EXPECT_THAT(mOffload->setDataWarningAndLimit(upstream, warning, limit).getExceptionCode(),
- AnyOf(Eq(EX_NONE), Eq(EX_UNSUPPORTED_OPERATION)));
+ auto ret = mOffload->setDataWarningAndLimit(upstream, warning, limit);
+ EXPECT_TRUE(ret.isOk()) << ret;
}
// TEST_IFACE is presumed to exist on the device and be up. No packets
@@ -433,8 +434,8 @@
const std::string upstream(TEST_IFACE);
const int64_t warning = 0LL;
const int64_t limit = 0LL;
- EXPECT_THAT(mOffload->setDataWarningAndLimit(upstream, warning, limit).getExceptionCode(),
- AnyOf(Eq(EX_NONE), Eq(EX_UNSUPPORTED_OPERATION)));
+ auto ret = mOffload->setDataWarningAndLimit(upstream, warning, limit);
+ EXPECT_TRUE(ret.isOk()) << ret;
}
// TEST_IFACE is presumed to exist on the device and be up. No packets
@@ -443,7 +444,8 @@
const std::string upstream(TEST_IFACE);
const int64_t warning = LLONG_MAX;
const int64_t limit = 5000LL;
- EXPECT_TRUE(mOffload->setDataWarningAndLimit(upstream, warning, limit).isOk());
+ auto ret = mOffload->setDataWarningAndLimit(upstream, warning, limit);
+ EXPECT_TRUE(ret.isOk()) << ret;
}
// Test that setDataWarningAndLimit() with negative thresholds fails.
@@ -451,8 +453,8 @@
const std::string upstream(TEST_IFACE);
const int64_t warning = -1LL;
const int64_t limit = -1LL;
- EXPECT_THAT(mOffload->setDataWarningAndLimit(upstream, warning, limit).getExceptionCode(),
- AnyOf(Eq(EX_ILLEGAL_ARGUMENT), Eq(EX_UNSUPPORTED_OPERATION)));
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT,
+ mOffload->setDataWarningAndLimit(upstream, warning, limit).getExceptionCode());
}
/*
@@ -466,7 +468,8 @@
const std::string v4Addr("");
const std::string v4Gw("");
const std::vector<std::string> v6Gws{std::string("fe80::db8:1"), std::string("fe80::db8:2")};
- EXPECT_TRUE(mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws).isOk());
+ auto ret = mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws);
+ EXPECT_TRUE(ret.isOk()) << ret;
}
// TEST_IFACE is presumed to exist on the device and be up. No packets
@@ -476,7 +479,8 @@
const std::string v4Addr("");
const std::string v4Gw("");
const std::vector<std::string> v6Gws{std::string("fe80::db8:1"), std::string("fe80::db8:3")};
- EXPECT_TRUE(mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws).isOk());
+ auto ret = mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws);
+ EXPECT_TRUE(ret.isOk()) << ret;
}
// TEST_IFACE is presumed to exist on the device and be up. No packets
@@ -486,7 +490,8 @@
const std::string v4Addr("192.0.2.2");
const std::string v4Gw("192.0.2.1");
const std::vector<std::string> v6Gws{};
- EXPECT_TRUE(mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws).isOk());
+ auto ret = mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws);
+ EXPECT_TRUE(ret.isOk()) << ret;
}
// TEST_IFACE is presumed to exist on the device and be up. No packets
@@ -496,7 +501,8 @@
const std::string v4Addr("192.0.2.2");
const std::string v4Gw("192.0.2.1");
const std::vector<std::string> v6Gws{std::string("fe80::db8:1"), std::string("fe80::db8:2")};
- EXPECT_TRUE(mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws).isOk());
+ auto ret = mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws);
+ EXPECT_TRUE(ret.isOk()) << ret;
}
// Test that setUpstreamParameters() fails when all parameters are empty.
@@ -505,8 +511,8 @@
const std::string v4Addr("");
const std::string v4Gw("");
const std::vector<std::string> v6Gws{};
- EXPECT_EQ(mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws).getExceptionCode(),
- EX_ILLEGAL_ARGUMENT);
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT,
+ mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws).getExceptionCode());
}
// Test that setUpstreamParameters() fails when given empty or non-existent interface names.
@@ -517,8 +523,8 @@
for (const auto& bogus : {"", "invalid"}) {
SCOPED_TRACE(testing::Message() << "upstream: " << bogus);
const std::string iface(bogus);
- EXPECT_EQ(mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws).getExceptionCode(),
- EX_ILLEGAL_ARGUMENT);
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT,
+ mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws).getExceptionCode());
}
}
@@ -530,8 +536,8 @@
for (const auto& bogus : {"invalid", "192.0.2"}) {
SCOPED_TRACE(testing::Message() << "v4addr: " << bogus);
const std::string v4Addr(bogus);
- EXPECT_EQ(mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws).getExceptionCode(),
- EX_ILLEGAL_ARGUMENT);
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT,
+ mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws).getExceptionCode());
}
}
@@ -543,8 +549,8 @@
for (const auto& bogus : {"invalid", "192.0.2"}) {
SCOPED_TRACE(testing::Message() << "v4gateway: " << bogus);
const std::string v4Gw(bogus);
- EXPECT_EQ(mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws).getExceptionCode(),
- EX_ILLEGAL_ARGUMENT);
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT,
+ mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws).getExceptionCode());
}
}
@@ -556,8 +562,8 @@
for (const auto& bogus : {"", "invalid", "fe80::bogus", "192.0.2.66"}) {
SCOPED_TRACE(testing::Message() << "v6gateway: " << bogus);
const std::vector<std::string> v6Gws{std::string("fe80::1"), std::string(bogus)};
- EXPECT_EQ(mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws).getExceptionCode(),
- EX_ILLEGAL_ARGUMENT);
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT,
+ mOffload->setUpstreamParameters(iface, v4Addr, v4Gw, v6Gws).getExceptionCode());
}
}
@@ -569,21 +575,23 @@
TEST_P(TetheroffloadAidlGeneralTest, AddDownstreamIPv4) {
const std::string iface("dummy0");
const std::string prefix("192.0.2.0/24");
- EXPECT_TRUE(mOffload->addDownstream(iface, prefix).isOk());
+ auto ret = mOffload->addDownstream(iface, prefix);
+ EXPECT_TRUE(ret.isOk()) << ret;
}
// Test addDownstream() works given an IPv6 prefix.
TEST_P(TetheroffloadAidlGeneralTest, AddDownstreamIPv6) {
const std::string iface("dummy0");
const std::string prefix("2001:db8::/64");
- EXPECT_TRUE(mOffload->addDownstream(iface, prefix).isOk());
+ auto ret = mOffload->addDownstream(iface, prefix);
+ EXPECT_TRUE(ret.isOk()) << ret;
}
// Test addDownstream() fails given all empty parameters.
TEST_P(TetheroffloadAidlGeneralTest, AddDownstreamEmptyFails) {
const std::string iface("");
const std::string prefix("");
- EXPECT_EQ(mOffload->addDownstream(iface, prefix).getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT, mOffload->addDownstream(iface, prefix).getExceptionCode());
}
// Test addDownstream() fails given empty or non-existent interface names.
@@ -592,7 +600,7 @@
for (const auto& bogus : {"", "invalid"}) {
SCOPED_TRACE(testing::Message() << "iface: " << bogus);
const std::string iface(bogus);
- EXPECT_EQ(mOffload->addDownstream(iface, prefix).getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT, mOffload->addDownstream(iface, prefix).getExceptionCode());
}
}
@@ -602,7 +610,7 @@
for (const auto& bogus : {"", "192.0.2/24", "2001:db8/64"}) {
SCOPED_TRACE(testing::Message() << "prefix: " << bogus);
const std::string prefix(bogus);
- EXPECT_EQ(mOffload->addDownstream(iface, prefix).getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT, mOffload->addDownstream(iface, prefix).getExceptionCode());
}
}
@@ -616,8 +624,10 @@
const std::string prefix("192.0.2.0/24");
// First add the downstream, otherwise removeDownstream logic can reasonably
// return error for downstreams not previously added.
- EXPECT_TRUE(mOffload->addDownstream(iface, prefix).isOk());
- EXPECT_TRUE(mOffload->removeDownstream(iface, prefix).isOk());
+ auto ret = mOffload->addDownstream(iface, prefix);
+ EXPECT_TRUE(ret.isOk()) << ret;
+ ret = mOffload->removeDownstream(iface, prefix);
+ EXPECT_TRUE(ret.isOk()) << ret;
}
// Test removeDownstream() works given an IPv6 prefix.
@@ -626,15 +636,17 @@
const std::string prefix("2001:db8::/64");
// First add the downstream, otherwise removeDownstream logic can reasonably
// return error for downstreams not previously added.
- EXPECT_TRUE(mOffload->addDownstream(iface, prefix).isOk());
- EXPECT_TRUE(mOffload->removeDownstream(iface, prefix).isOk());
+ auto ret = mOffload->addDownstream(iface, prefix);
+ EXPECT_TRUE(ret.isOk()) << ret;
+ ret = mOffload->removeDownstream(iface, prefix);
+ EXPECT_TRUE(ret.isOk()) << ret;
}
// Test removeDownstream() fails given all empty parameters.
TEST_P(TetheroffloadAidlGeneralTest, RemoveDownstreamEmptyFails) {
const std::string iface("");
const std::string prefix("");
- EXPECT_EQ(mOffload->removeDownstream(iface, prefix).getExceptionCode(), EX_ILLEGAL_ARGUMENT);
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT, mOffload->removeDownstream(iface, prefix).getExceptionCode());
}
// Test removeDownstream() fails given empty or non-existent interface names.
@@ -643,8 +655,8 @@
for (const auto& bogus : {"", "invalid"}) {
SCOPED_TRACE(testing::Message() << "iface: " << bogus);
const std::string iface(bogus);
- EXPECT_EQ(mOffload->removeDownstream(iface, prefix).getExceptionCode(),
- EX_ILLEGAL_ARGUMENT);
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT,
+ mOffload->removeDownstream(iface, prefix).getExceptionCode());
}
}
@@ -654,8 +666,8 @@
for (const auto& bogus : {"", "192.0.2/24", "2001:db8/64"}) {
SCOPED_TRACE(testing::Message() << "prefix: " << bogus);
const std::string prefix(bogus);
- EXPECT_EQ(mOffload->removeDownstream(iface, prefix).getExceptionCode(),
- EX_ILLEGAL_ARGUMENT);
+ EXPECT_EQ(EX_ILLEGAL_ARGUMENT,
+ mOffload->removeDownstream(iface, prefix).getExceptionCode());
}
}
diff --git a/thermal/aidl/android/hardware/thermal/IThermal.aidl b/thermal/aidl/android/hardware/thermal/IThermal.aidl
index 7c23c17..c94edcd 100644
--- a/thermal/aidl/android/hardware/thermal/IThermal.aidl
+++ b/thermal/aidl/android/hardware/thermal/IThermal.aidl
@@ -36,9 +36,8 @@
* exist on boot. The method always returns and never removes from
* the list such cooling devices.
*
- * @throws ScopedAStatus Status of the operation. If status code is not
- * STATUS_OK, getMessage() must be populated with the human-readable
- * error message.
+ * @throws EX_ILLEGAL_STATE If the Thermal HAL is not initialized successfully. And the
+ * getMessage() must be populated with human-readable error message.
*/
CoolingDevice[] getCoolingDevices();
@@ -54,9 +53,8 @@
* exist on boot. The method always returns and never removes from
* the list such cooling devices.
*
- * @throws ScopedAStatus Status of the operation. If status code is not
- * STATUS_OK, the getMessage() must be populated with the human-readable
- * error message.
+ * @throws EX_ILLEGAL_STATE If the Thermal HAL is not initialized successfully. And the
+ * getMessage() must be populated with human-readable error message.
*/
CoolingDevice[] getCoolingDevicesWithType(in CoolingType type);
@@ -70,9 +68,8 @@
* they go offline, if these devices exist on boot. The method
* always returns and never removes such temperatures.
*
- * @throws ScopedAStatus Status of the operation. If status code is not
- * STATUS_OK, the getMessage() must be populated with the human-readable
- * error message.
+ * @throws EX_ILLEGAL_STATE If the Thermal HAL is not initialized successfully. And the
+ * getMessage() must be populated with human-readable error message.
*/
Temperature[] getTemperatures();
@@ -88,9 +85,8 @@
* they go offline, if these devices exist on boot. The method
* always returns and never removes such temperatures.
*
- * @throws ScopedAStatus Status of the operation. If status code is not
- * STATUS_OK, the getMessage() must be populated with the human-readable
- * error message.
+ * @throws EX_ILLEGAL_STATE If the Thermal HAL is not initialized successfully. And the
+ * getMessage() must be populated with human-readable error message.
*/
Temperature[] getTemperaturesWithType(in TemperatureType type);
@@ -110,9 +106,8 @@
* throttling status, use getTemperatures or registerThermalChangedCallback
* and listen to the callback.
*
- * @throws ScopedAStatus Status of the operation. If status code is not
- * STATUS_OK, the getMessage() must be populated with the human-readable
- * error message.
+ * @throws EX_ILLEGAL_STATE If the Thermal HAL is not initialized successfully. And the
+ * getMessage() must be populated with human-readable error message.
*/
TemperatureThreshold[] getTemperatureThresholds();
@@ -135,9 +130,8 @@
* throttling status, use getTemperatures or registerThermalChangedCallback
* and listen to the callback.
*
- * @throws ScopedAStatus Status of the operation. If status code is not
- * STATUS_OK, the getMessage() must be populated with the human-readable
- * error message.
+ * @throws EX_ILLEGAL_STATE If the Thermal HAL is not initialized successfully. And the
+ * getMessage() must be populated with human-readable error message.
*/
TemperatureThreshold[] getTemperatureThresholdsWithType(in TemperatureType type);
@@ -152,12 +146,10 @@
* thermal events. if nullptr callback is given, the status code will be
* STATUS_BAD_VALUE and the operation will fail.
*
- * @throws ScopedAStatus Status of the operation. If status code is not
- * STATUS_OK, the getMessage() must be populated with the human-readable
- * error message. If callback is given nullptr, the returned status code
- * will be STATUS_BAD_VALUE and the exception will be EX_ILLEGAL_ARGUMENT.
- * if callback is already registered, the returned status code will be
- * STATUS_INVALID_OPERATION, the exception will be EX_ILLEGAL_ARGUMENT.
+ * @throws EX_ILLEGAL_ARGUMENT If the callback is given nullptr or already registered. And the
+ * getMessage() must be populated with human-readable error message.
+ * @throws EX_ILLEGAL_STATE If the Thermal HAL is not initialized successfully. And the
+ * getMessage() must be populated with human-readable error message.
*/
void registerThermalChangedCallback(in IThermalChangedCallback callback);
@@ -174,12 +166,10 @@
* STATUS_BAD_VALUE and the operation will fail.
* @param type the type to be filtered.
*
- * @throws ScopedAStatus Status of the operation. If status code is not
- * STATUS_OK, the getMessage() must be populated with the human-readable
- * error message. If callback is given nullptr, the returned status code
- * will be STATUS_BAD_VALUE and the exception will be EX_ILLEGAL_ARGUMENT.
- * if callback is already registered, the returned status code will be
- * STATUS_INVALID_OPERATION, the exception will be EX_ILLEGAL_ARGUMENT.
+ * @throws EX_ILLEGAL_ARGUMENT If the callback is given nullptr or already registered. And the
+ * getMessage() must be populated with human-readable error message.
+ * @throws EX_ILLEGAL_STATE If the Thermal HAL is not initialized successfully. And the
+ * getMessage() must be populated with human-readable error message.
*/
void registerThermalChangedCallbackWithType(
in IThermalChangedCallback callback, in TemperatureType type);
@@ -192,12 +182,10 @@
* thermal events. if nullptr callback is given, the status code will be
* STATUS_BAD_VALUE and the operation will fail.
*
- * @throws ScopedAStatus Status of the operation. If status code is not
- * STATUS_OK, the getMessage() must be populated with the human-readable
- * error message. If callback is given nullptr, the returned status code
- * will be STATUS_BAD_VALUE and the exception will be EX_ILLEGAL_ARGUMENT.
- * if callback is not registered, the returned status code will be
- * STATUS_INVALID_OPERATION, the exception will be EX_ILLEGAL_ARGUMENT.
+ * @throws EX_ILLEGAL_ARGUMENT If the callback is given nullptr or not previously registered.
+ * And the getMessage() must be populated with human-readable error message.
+ * @throws EX_ILLEGAL_STATE If the Thermal HAL is not initialized successfully. And the
+ * getMessage() must be populated with human-readable error message.
*/
void unregisterThermalChangedCallback(in IThermalChangedCallback callback);
}
diff --git a/thermal/aidl/default/Thermal.cpp b/thermal/aidl/default/Thermal.cpp
index 5771e0e..f643d22 100644
--- a/thermal/aidl/default/Thermal.cpp
+++ b/thermal/aidl/default/Thermal.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "thermal_service_example"
+
#include "Thermal.h"
#include <android-base/logging.h>
@@ -22,6 +24,18 @@
using ndk::ScopedAStatus;
+namespace {
+
+bool interfacesEqual(const std::shared_ptr<::ndk::ICInterface>& left,
+ const std::shared_ptr<::ndk::ICInterface>& right) {
+ if (left == nullptr || right == nullptr || !left->isRemote() || !right->isRemote()) {
+ return left == right;
+ }
+ return left->asBinder() == right->asBinder();
+}
+
+} // namespace
+
ScopedAStatus Thermal::getCoolingDevices(std::vector<CoolingDevice>* /* out_devices */) {
LOG(VERBOSE) << __func__;
return ScopedAStatus::ok();
@@ -61,12 +75,20 @@
const std::shared_ptr<IThermalChangedCallback>& in_callback) {
LOG(VERBOSE) << __func__ << " IThermalChangedCallback: " << in_callback;
if (in_callback == nullptr) {
- return ScopedAStatus::fromStatus(STATUS_BAD_VALUE);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "Invalid nullptr callback");
}
- if (mCallbacks.find(in_callback) != mCallbacks.end()) {
- return ScopedAStatus::fromStatus(STATUS_INVALID_OPERATION);
+ {
+ std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
+ if (std::any_of(thermal_callbacks_.begin(), thermal_callbacks_.end(),
+ [&](const std::shared_ptr<IThermalChangedCallback>& c) {
+ return interfacesEqual(c, in_callback);
+ })) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "Callback already registered");
+ }
+ thermal_callbacks_.push_back(in_callback);
}
- mCallbacks.insert(in_callback);
return ScopedAStatus::ok();
}
@@ -75,26 +97,48 @@
LOG(VERBOSE) << __func__ << " IThermalChangedCallback: " << in_callback
<< ", TemperatureType: " << static_cast<int32_t>(in_type);
if (in_callback == nullptr) {
- return ScopedAStatus::fromStatus(STATUS_BAD_VALUE);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "Invalid nullptr callback");
}
- if (mCallbacks.find(in_callback) != mCallbacks.end()) {
- return ScopedAStatus::fromStatus(STATUS_INVALID_OPERATION);
+ {
+ std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
+ if (std::any_of(thermal_callbacks_.begin(), thermal_callbacks_.end(),
+ [&](const std::shared_ptr<IThermalChangedCallback>& c) {
+ return interfacesEqual(c, in_callback);
+ })) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "Callback already registered");
+ }
+ thermal_callbacks_.push_back(in_callback);
}
- mCallbacks.insert(in_callback);
return ScopedAStatus::ok();
}
ScopedAStatus Thermal::unregisterThermalChangedCallback(
const std::shared_ptr<IThermalChangedCallback>& in_callback) {
LOG(VERBOSE) << __func__ << " IThermalChangedCallback: " << in_callback;
- bool found = false;
if (in_callback == nullptr) {
- return ScopedAStatus::fromStatus(STATUS_BAD_VALUE);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "Invalid nullptr callback");
}
- if (mCallbacks.find(in_callback) == mCallbacks.end()) {
- return ScopedAStatus::fromStatus(STATUS_INVALID_OPERATION);
+ {
+ std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
+ bool removed = false;
+ thermal_callbacks_.erase(
+ std::remove_if(thermal_callbacks_.begin(), thermal_callbacks_.end(),
+ [&](const std::shared_ptr<IThermalChangedCallback>& c) {
+ if (interfacesEqual(c, in_callback)) {
+ removed = true;
+ return true;
+ }
+ return false;
+ }),
+ thermal_callbacks_.end());
+ if (!removed) {
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "Callback wasn't registered");
+ }
}
- mCallbacks.erase(in_callback);
return ScopedAStatus::ok();
}
diff --git a/thermal/aidl/default/Thermal.h b/thermal/aidl/default/Thermal.h
index 788af4a..8885e63 100644
--- a/thermal/aidl/default/Thermal.h
+++ b/thermal/aidl/default/Thermal.h
@@ -54,7 +54,8 @@
const std::shared_ptr<IThermalChangedCallback>& in_callback) override;
private:
- std::set<std::shared_ptr<IThermalChangedCallback>> mCallbacks;
+ std::mutex thermal_callback_mutex_;
+ std::vector<std::shared_ptr<IThermalChangedCallback>> thermal_callbacks_;
};
} // namespace example
diff --git a/thermal/aidl/default/main.cpp b/thermal/aidl/default/main.cpp
index 61d8ad0..9f4ddb8 100644
--- a/thermal/aidl/default/main.cpp
+++ b/thermal/aidl/default/main.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "thermal_service_example"
+
#include "Thermal.h"
#include <android-base/logging.h>
diff --git a/thermal/aidl/vts/VtsHalThermalTargetTest.cpp b/thermal/aidl/vts/VtsHalThermalTargetTest.cpp
index b93250e..73c5dd2 100644
--- a/thermal/aidl/vts/VtsHalThermalTargetTest.cpp
+++ b/thermal/aidl/vts/VtsHalThermalTargetTest.cpp
@@ -95,21 +95,21 @@
mThermalCallback = ndk::SharedRefBase::make<ThermalCallback>();
ASSERT_NE(mThermalCallback, nullptr);
- auto ret = mThermal->registerThermalChangedCallback(mThermalCallback);
- ASSERT_TRUE(ret.isOk());
+ auto status = mThermal->registerThermalChangedCallback(mThermalCallback);
+ ASSERT_TRUE(status.isOk());
// Expect to fail if register again
- ret = mThermal->registerThermalChangedCallback(mThermalCallback);
- ASSERT_FALSE(ret.isOk());
- ASSERT_TRUE(ret.getStatus() == STATUS_INVALID_OPERATION);
+ status = mThermal->registerThermalChangedCallback(mThermalCallback);
+ ASSERT_FALSE(status.isOk());
+ ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
}
void TearDown() override {
- auto ret = mThermal->unregisterThermalChangedCallback(mThermalCallback);
- ASSERT_TRUE(ret.isOk());
+ auto status = mThermal->unregisterThermalChangedCallback(mThermalCallback);
+ ASSERT_TRUE(status.isOk());
// Expect to fail if unregister again
- ret = mThermal->unregisterThermalChangedCallback(mThermalCallback);
- ASSERT_FALSE(ret.isOk());
- ASSERT_TRUE(ret.getStatus() == STATUS_INVALID_OPERATION);
+ status = mThermal->unregisterThermalChangedCallback(mThermalCallback);
+ ASSERT_FALSE(status.isOk());
+ ASSERT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
}
protected:
diff --git a/usb/gadget/aidl/default/UsbGadget.cpp b/usb/gadget/aidl/default/UsbGadget.cpp
index 72cf681..51f7f5b 100644
--- a/usb/gadget/aidl/default/UsbGadget.cpp
+++ b/usb/gadget/aidl/default/UsbGadget.cpp
@@ -91,6 +91,9 @@
ScopedAStatus UsbGadget::getCurrentUsbFunctions(const shared_ptr<IUsbGadgetCallback>& callback,
int64_t in_transactionId) {
+ if (callback == nullptr) {
+ return ScopedAStatus::fromExceptionCode(EX_NULL_POINTER);
+ }
ScopedAStatus ret = callback->getCurrentUsbFunctionsCb(
mCurrentUsbFunctions,
mCurrentUsbFunctionsApplied ? Status::FUNCTIONS_APPLIED : Status::FUNCTIONS_NOT_APPLIED,