Merge changes Icc5d023c,I3a2246c1 into main
* changes:
Add script to parse VehicleProperty.aidl to CSV.
Minor update on access annotation.
diff --git a/audio/aidl/TEST_MAPPING b/audio/aidl/TEST_MAPPING
index 12bce0b..81c99f7 100644
--- a/audio/aidl/TEST_MAPPING
+++ b/audio/aidl/TEST_MAPPING
@@ -4,9 +4,6 @@
"name": "VtsHalAudioCoreTargetTest"
},
{
- "name": "VtsHalAudioCoreConfigTargetTest"
- },
- {
"name": "audio_policy_config_xml_converter_tests"
},
{
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 78b59d4..19b2397 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -73,18 +73,23 @@
"Configuration.cpp",
"EngineConfigXmlConverter.cpp",
"Module.cpp",
+ "ModulePrimary.cpp",
"SoundDose.cpp",
"Stream.cpp",
- "StreamStub.cpp",
"Telephony.cpp",
+ "alsa/Mixer.cpp",
+ "alsa/ModuleAlsa.cpp",
+ "alsa/StreamAlsa.cpp",
+ "alsa/Utils.cpp",
"r_submix/ModuleRemoteSubmix.cpp",
"r_submix/RemoteSubmixUtils.cpp",
"r_submix/SubmixRoute.cpp",
"r_submix/StreamRemoteSubmix.cpp",
+ "stub/ModuleStub.cpp",
+ "stub/StreamStub.cpp",
"usb/ModuleUsb.cpp",
"usb/StreamUsb.cpp",
"usb/UsbAlsaMixerControl.cpp",
- "usb/UsbAlsaUtils.cpp",
],
generated_sources: [
"audio_policy_configuration_aidl_default",
diff --git a/audio/aidl/default/Configuration.cpp b/audio/aidl/default/Configuration.cpp
index d41ea67..a71c6ea 100644
--- a/audio/aidl/default/Configuration.cpp
+++ b/audio/aidl/default/Configuration.cpp
@@ -144,10 +144,6 @@
// - no profiles specified
// * "FM Tuner", IN_FM_TUNER
// - no profiles specified
-// * "USB Out", OUT_DEVICE, CONNECTION_USB
-// - no profiles specified
-// * "USB In", IN_DEVICE, CONNECTION_USB
-// - no profiles specified
//
// Mix ports:
// * "primary output", PRIMARY, 1 max open, 1 max active stream
@@ -172,8 +168,7 @@
//
// Routes:
// "primary out", "compressed offload" -> "Speaker"
-// "primary out", "compressed offload" -> "USB Out"
-// "Built-in Mic", "USB In" -> "primary input"
+// "Built-in Mic" -> "primary input"
// "telephony_tx" -> "Telephony Tx"
// "Telephony Rx" -> "telephony_rx"
// "FM Tuner" -> "fm_tuner"
@@ -185,14 +180,6 @@
// * "Telephony Rx" device port: PCM 24-bit; MONO; 48000
// * "FM Tuner" device port: PCM 24-bit; STEREO; 48000
//
-// Profiles for device port connected state:
-// * USB Out":
-// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-// * USB In":
-// - profile PCM 16-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
-//
std::unique_ptr<Configuration> getPrimaryConfiguration() {
static const Configuration configuration = []() {
const std::vector<AudioProfile> standardPcmAudioProfiles = {
@@ -252,19 +239,6 @@
AudioChannelLayout::LAYOUT_STEREO, 48000, 0, true,
createDeviceExt(AudioDeviceType::IN_FM_TUNER, 0)));
- AudioPort usbOutDevice =
- createPort(c.nextPortId++, "USB Out", 0, false,
- createDeviceExt(AudioDeviceType::OUT_DEVICE, 0,
- AudioDeviceDescription::CONNECTION_USB));
- c.ports.push_back(usbOutDevice);
- c.connectedProfiles[usbOutDevice.id] = standardPcmAudioProfiles;
-
- AudioPort usbInDevice = createPort(c.nextPortId++, "USB In", 0, true,
- createDeviceExt(AudioDeviceType::IN_DEVICE, 0,
- AudioDeviceDescription::CONNECTION_USB));
- c.ports.push_back(usbInDevice);
- c.connectedProfiles[usbInDevice.id] = standardPcmAudioProfiles;
-
// Mix ports
AudioPort primaryOutMix = createPort(c.nextPortId++, "primary output",
@@ -323,8 +297,7 @@
c.ports.push_back(fmTunerInMix);
c.routes.push_back(createRoute({primaryOutMix, compressedOffloadOutMix}, speakerOutDevice));
- c.routes.push_back(createRoute({primaryOutMix, compressedOffloadOutMix}, usbOutDevice));
- c.routes.push_back(createRoute({micInDevice, usbInDevice}, primaryInMix));
+ c.routes.push_back(createRoute({micInDevice}, primaryInMix));
c.routes.push_back(createRoute({telephonyTxOutMix}, telephonyTxOutDevice));
c.routes.push_back(createRoute({telephonyRxInDevice}, telephonyRxInMix));
c.routes.push_back(createRoute({fmTunerInDevice}, fmTunerInMix));
@@ -406,22 +379,31 @@
// Usb configuration:
//
// Device ports:
+// * "USB Device Out", OUT_DEVICE, CONNECTION_USB
+// - no profiles specified
// * "USB Headset Out", OUT_HEADSET, CONNECTION_USB
// - no profiles specified
+// * "USB Device In", IN_DEVICE, CONNECTION_USB
+// - no profiles specified
// * "USB Headset In", IN_HEADSET, CONNECTION_USB
// - no profiles specified
//
// Mix ports:
-// * "usb_headset output", 1 max open, 1 max active stream
+// * "usb_device output", 1 max open, 1 max active stream
// - no profiles specified
-// * "usb_headset input", 1 max open, 1 max active stream
+// * "usb_device input", 1 max open, 1 max active stream
// - no profiles specified
//
+// Routes:
+// * "usb_device output" -> "USB Device Out"
+// * "usb_device output" -> "USB Headset Out"
+// * "USB Device In", "USB Headset In" -> "usb_device input"
+//
// Profiles for device port connected state:
-// * USB Headset Out":
+// * "USB Device Out", "USB Headset Out":
// - profile PCM 16-bit; MONO, STEREO, INDEX_MASK_1, INDEX_MASK_2; 44100, 48000
// - profile PCM 24-bit; MONO, STEREO, INDEX_MASK_1, INDEX_MASK_2; 44100, 48000
-// * USB Headset In":
+// * "USB Device In", "USB Headset In":
// - profile PCM 16-bit; MONO, STEREO, INDEX_MASK_1, INDEX_MASK_2; 44100, 48000
// - profile PCM 24-bit; MONO, STEREO, INDEX_MASK_1, INDEX_MASK_2; 44100, 48000
//
@@ -440,6 +422,13 @@
// Device ports
+ AudioPort usbOutDevice =
+ createPort(c.nextPortId++, "USB Device Out", 0, false,
+ createDeviceExt(AudioDeviceType::OUT_DEVICE, 0,
+ AudioDeviceDescription::CONNECTION_USB));
+ c.ports.push_back(usbOutDevice);
+ c.connectedProfiles[usbOutDevice.id] = standardPcmAudioProfiles;
+
AudioPort usbOutHeadset =
createPort(c.nextPortId++, "USB Headset Out", 0, false,
createDeviceExt(AudioDeviceType::OUT_HEADSET, 0,
@@ -447,6 +436,12 @@
c.ports.push_back(usbOutHeadset);
c.connectedProfiles[usbOutHeadset.id] = standardPcmAudioProfiles;
+ AudioPort usbInDevice = createPort(c.nextPortId++, "USB Device In", 0, true,
+ createDeviceExt(AudioDeviceType::IN_DEVICE, 0,
+ AudioDeviceDescription::CONNECTION_USB));
+ c.ports.push_back(usbInDevice);
+ c.connectedProfiles[usbInDevice.id] = standardPcmAudioProfiles;
+
AudioPort usbInHeadset =
createPort(c.nextPortId++, "USB Headset In", 0, true,
createDeviceExt(AudioDeviceType::IN_HEADSET, 0,
@@ -456,16 +451,110 @@
// Mix ports
- AudioPort usbHeadsetOutMix =
- createPort(c.nextPortId++, "usb_headset output", 0, false, createPortMixExt(1, 1));
- c.ports.push_back(usbHeadsetOutMix);
+ AudioPort usbDeviceOutMix =
+ createPort(c.nextPortId++, "usb_device output", 0, false, createPortMixExt(1, 1));
+ c.ports.push_back(usbDeviceOutMix);
- AudioPort usbHeadsetInMix =
- createPort(c.nextPortId++, "usb_headset input", 0, true, createPortMixExt(1, 1));
- c.ports.push_back(usbHeadsetInMix);
+ AudioPort usbDeviceInMix =
+ createPort(c.nextPortId++, "usb_device input", 0, true, createPortMixExt(1, 1));
+ c.ports.push_back(usbDeviceInMix);
- c.routes.push_back(createRoute({usbHeadsetOutMix}, usbOutHeadset));
- c.routes.push_back(createRoute({usbInHeadset}, usbHeadsetInMix));
+ c.routes.push_back(createRoute({usbDeviceOutMix}, usbOutDevice));
+ c.routes.push_back(createRoute({usbDeviceOutMix}, usbOutHeadset));
+ c.routes.push_back(createRoute({usbInDevice, usbInHeadset}, usbDeviceInMix));
+
+ return c;
+ }();
+ return std::make_unique<Configuration>(configuration);
+}
+
+// Stub configuration:
+//
+// Device ports:
+// * "Test Out", OUT_AFE_PROXY
+// - no profiles specified
+// * "Test In", IN_AFE_PROXY
+// - no profiles specified
+//
+// Mix ports:
+// * "test output", 1 max open, 1 max active stream
+// - profile PCM 24-bit; MONO, STEREO; 8000, 11025, 16000, 32000, 44100, 48000
+// * "compressed offload", DIRECT|COMPRESS_OFFLOAD|NON_BLOCKING, 1 max open, 1 max active stream
+// - profile MP3; MONO, STEREO; 44100, 48000
+// * "test input", 2 max open, 2 max active streams
+// - profile PCM 24-bit; MONO, STEREO, FRONT_BACK;
+// 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+//
+// Routes:
+// "test output", "compressed offload" -> "Test Out"
+// "Test In" -> "test input"
+//
+// Initial port configs:
+// * "Test Out" device port: PCM 24-bit; STEREO; 48000
+// * "Test In" device port: PCM 24-bit; MONO; 48000
+//
+std::unique_ptr<Configuration> getStubConfiguration() {
+ static const Configuration configuration = []() {
+ Configuration c;
+
+ // Device ports
+
+ AudioPort testOutDevice = createPort(c.nextPortId++, "Test Out", 0, false,
+ createDeviceExt(AudioDeviceType::OUT_AFE_PROXY, 0));
+ c.ports.push_back(testOutDevice);
+ c.initialConfigs.push_back(
+ createPortConfig(testOutDevice.id, testOutDevice.id, PcmType::INT_24_BIT,
+ AudioChannelLayout::LAYOUT_STEREO, 48000, 0, false,
+ createDeviceExt(AudioDeviceType::OUT_AFE_PROXY, 0)));
+
+ AudioPort testInDevice = createPort(c.nextPortId++, "Test In", 0, true,
+ createDeviceExt(AudioDeviceType::IN_AFE_PROXY, 0));
+ c.ports.push_back(testInDevice);
+ c.initialConfigs.push_back(
+ createPortConfig(testInDevice.id, testInDevice.id, PcmType::INT_24_BIT,
+ AudioChannelLayout::LAYOUT_MONO, 48000, 0, true,
+ createDeviceExt(AudioDeviceType::IN_AFE_PROXY, 0)));
+
+ // Mix ports
+
+ AudioPort testOutMix =
+ createPort(c.nextPortId++, "test output", 0, false, createPortMixExt(1, 1));
+ testOutMix.profiles.push_back(
+ createProfile(PcmType::INT_24_BIT,
+ {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
+ {8000, 11025, 16000, 32000, 44100, 48000}));
+ c.ports.push_back(testOutMix);
+
+ AudioPort compressedOffloadOutMix =
+ createPort(c.nextPortId++, "compressed offload",
+ makeBitPositionFlagMask({AudioOutputFlags::DIRECT,
+ AudioOutputFlags::COMPRESS_OFFLOAD,
+ AudioOutputFlags::NON_BLOCKING}),
+ false, createPortMixExt(1, 1));
+ compressedOffloadOutMix.profiles.push_back(
+ createProfile(::android::MEDIA_MIMETYPE_AUDIO_MPEG,
+ {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO},
+ {44100, 48000}));
+ c.ports.push_back(compressedOffloadOutMix);
+
+ AudioPort testInMIx =
+ createPort(c.nextPortId++, "test input", 0, true, createPortMixExt(2, 2));
+ testInMIx.profiles.push_back(
+ createProfile(PcmType::INT_16_BIT,
+ {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO,
+ AudioChannelLayout::LAYOUT_FRONT_BACK},
+ {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}));
+ testInMIx.profiles.push_back(
+ createProfile(PcmType::INT_24_BIT,
+ {AudioChannelLayout::LAYOUT_MONO, AudioChannelLayout::LAYOUT_STEREO,
+ AudioChannelLayout::LAYOUT_FRONT_BACK},
+ {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}));
+ c.ports.push_back(testInMIx);
+
+ c.routes.push_back(createRoute({testOutMix, compressedOffloadOutMix}, testOutDevice));
+ c.routes.push_back(createRoute({testInDevice}, testInMIx));
+
+ c.portConfigs.insert(c.portConfigs.end(), c.initialConfigs.begin(), c.initialConfigs.end());
return c;
}();
diff --git a/audio/aidl/default/EffectConfig.cpp b/audio/aidl/default/EffectConfig.cpp
index f3f674f..730c0bf 100644
--- a/audio/aidl/default/EffectConfig.cpp
+++ b/audio/aidl/default/EffectConfig.cpp
@@ -117,53 +117,59 @@
bool EffectConfig::parseEffect(const tinyxml2::XMLElement& xml) {
struct EffectLibraries effectLibraries;
- std::vector<LibraryUuid> libraryUuids;
+ std::vector<Library> libraries;
std::string name = xml.Attribute("name");
RETURN_VALUE_IF(name == "", false, "effectsNoName");
LOG(DEBUG) << __func__ << dump(xml);
- struct LibraryUuid libraryUuid;
+ struct Library library;
if (std::strcmp(xml.Name(), "effectProxy") == 0) {
// proxy lib and uuid
- RETURN_VALUE_IF(!parseLibraryUuid(xml, libraryUuid, true), false, "parseProxyLibFailed");
- effectLibraries.proxyLibrary = libraryUuid;
+ RETURN_VALUE_IF(!parseLibrary(xml, library, true), false, "parseProxyLibFailed");
+ effectLibraries.proxyLibrary = library;
// proxy effect libs and UUID
auto xmlProxyLib = xml.FirstChildElement();
RETURN_VALUE_IF(!xmlProxyLib, false, "noLibForProxy");
while (xmlProxyLib) {
- struct LibraryUuid tempLibraryUuid;
- RETURN_VALUE_IF(!parseLibraryUuid(*xmlProxyLib, tempLibraryUuid), false,
+ struct Library tempLibrary;
+ RETURN_VALUE_IF(!parseLibrary(*xmlProxyLib, tempLibrary), false,
"parseEffectLibFailed");
- libraryUuids.push_back(std::move(tempLibraryUuid));
+ libraries.push_back(std::move(tempLibrary));
xmlProxyLib = xmlProxyLib->NextSiblingElement();
}
} else {
// expect only one library if not proxy
- RETURN_VALUE_IF(!parseLibraryUuid(xml, libraryUuid), false, "parseEffectLibFailed");
- libraryUuids.push_back(std::move(libraryUuid));
+ RETURN_VALUE_IF(!parseLibrary(xml, library), false, "parseEffectLibFailed");
+ libraries.push_back(std::move(library));
}
- effectLibraries.libraries = std::move(libraryUuids);
+ effectLibraries.libraries = std::move(libraries);
mEffectsMap[name] = std::move(effectLibraries);
return true;
}
-bool EffectConfig::parseLibraryUuid(const tinyxml2::XMLElement& xml,
- struct LibraryUuid& libraryUuid, bool isProxy) {
+bool EffectConfig::parseLibrary(const tinyxml2::XMLElement& xml, struct Library& library,
+ bool isProxy) {
// Retrieve library name only if not effectProxy element
if (!isProxy) {
const char* name = xml.Attribute("library");
RETURN_VALUE_IF(!name, false, "noLibraryAttribute");
- libraryUuid.name = name;
+ library.name = name;
}
const char* uuidStr = xml.Attribute("uuid");
RETURN_VALUE_IF(!uuidStr, false, "noUuidAttribute");
- libraryUuid.uuid = stringToUuid(uuidStr);
- RETURN_VALUE_IF((libraryUuid.uuid == getEffectUuidZero()), false, "invalidUuidAttribute");
+ library.uuid = stringToUuid(uuidStr);
+ if (const char* typeUuidStr = xml.Attribute("type")) {
+ library.type = stringToUuid(typeUuidStr);
+ }
+ RETURN_VALUE_IF((library.uuid == getEffectUuidZero()), false, "invalidUuidAttribute");
- LOG(DEBUG) << __func__ << (isProxy ? " proxy " : libraryUuid.name) << " : "
- << ::android::audio::utils::toString(libraryUuid.uuid);
+ LOG(DEBUG) << __func__ << (isProxy ? " proxy " : library.name) << " : uuid "
+ << ::android::audio::utils::toString(library.uuid)
+ << (library.type.has_value()
+ ? ::android::audio::utils::toString(library.type.value())
+ : "");
return true;
}
@@ -241,7 +247,8 @@
return mProcessingMap;
}
-bool EffectConfig::findUuid(const std::string& xmlEffectName, AudioUuid* uuid) {
+bool EffectConfig::findUuid(const std::pair<std::string, struct EffectLibraries>& effectElem,
+ AudioUuid* uuid) {
// Difference from EFFECT_TYPE_LIST_DEF, there could be multiple name mapping to same Effect Type
#define EFFECT_XML_TYPE_LIST_DEF(V) \
V("acoustic_echo_canceler", AcousticEchoCanceler) \
@@ -268,6 +275,7 @@
#define GENERATE_MAP_ENTRY_V(s, symbol) {s, &getEffectTypeUuid##symbol},
+ const std::string xmlEffectName = effectElem.first;
typedef const AudioUuid& (*UuidGetter)(void);
static const std::map<std::string, UuidGetter> uuidMap{
// std::make_pair("s", &getEffectTypeUuidExtension)};
@@ -276,6 +284,14 @@
*uuid = (*it->second)();
return true;
}
+
+ const auto& libs = effectElem.second.libraries;
+ for (const auto& lib : libs) {
+ if (lib.type.has_value()) {
+ *uuid = lib.type.value();
+ return true;
+ }
+ }
return false;
}
diff --git a/audio/aidl/default/EffectFactory.cpp b/audio/aidl/default/EffectFactory.cpp
index 8ed62c9..96f13ba 100644
--- a/audio/aidl/default/EffectFactory.cpp
+++ b/audio/aidl/default/EffectFactory.cpp
@@ -49,18 +49,18 @@
if (auto spEffect = it.first.lock()) {
LOG(ERROR) << __func__ << " erase remaining instance UUID "
<< ::android::audio::utils::toString(it.second.first);
- destroyEffectImpl(spEffect);
+ destroyEffectImpl_l(spEffect);
}
}
}
}
-ndk::ScopedAStatus Factory::getDescriptorWithUuid(const AudioUuid& uuid, Descriptor* desc) {
+ndk::ScopedAStatus Factory::getDescriptorWithUuid_l(const AudioUuid& uuid, Descriptor* desc) {
RETURN_IF(!desc, EX_NULL_POINTER, "nullDescriptor");
if (mEffectLibMap.count(uuid)) {
auto& entry = mEffectLibMap[uuid];
- getDlSyms(entry);
+ getDlSyms_l(entry);
auto& libInterface = std::get<kMapEntryInterfaceIndex>(entry);
RETURN_IF(!libInterface || !libInterface->queryEffectFunc, EX_NULL_POINTER,
"dlNullQueryEffectFunc");
@@ -75,6 +75,7 @@
const std::optional<AudioUuid>& in_impl_uuid,
const std::optional<AudioUuid>& in_proxy_uuid,
std::vector<Descriptor>* _aidl_return) {
+ std::lock_guard lg(mMutex);
// get the matching list
std::vector<Descriptor::Identity> idList;
std::copy_if(mIdentitySet.begin(), mIdentitySet.end(), std::back_inserter(idList),
@@ -88,7 +89,8 @@
for (const auto& id : idList) {
if (mEffectLibMap.count(id.uuid)) {
Descriptor desc;
- RETURN_IF_ASTATUS_NOT_OK(getDescriptorWithUuid(id.uuid, &desc), "getDescriptorFailed");
+ RETURN_IF_ASTATUS_NOT_OK(getDescriptorWithUuid_l(id.uuid, &desc),
+ "getDescriptorFailed");
// update proxy UUID with information from config xml
desc.common.id.proxy = id.proxy;
_aidl_return->emplace_back(std::move(desc));
@@ -99,18 +101,19 @@
ndk::ScopedAStatus Factory::queryProcessing(const std::optional<Processing::Type>& in_type,
std::vector<Processing>* _aidl_return) {
+ std::lock_guard lg(mMutex);
const auto& processings = mConfig.getProcessingMap();
// Processing stream type
for (const auto& procIter : processings) {
if (!in_type.has_value() || in_type.value() == procIter.first) {
Processing process = {.type = procIter.first /* Processing::Type */};
for (const auto& libs : procIter.second /* std::vector<struct EffectLibraries> */) {
- for (const auto& lib : libs.libraries /* std::vector<struct LibraryUuid> */) {
+ for (const auto& lib : libs.libraries /* std::vector<struct Library> */) {
Descriptor desc;
if (libs.proxyLibrary.has_value()) {
desc.common.id.proxy = libs.proxyLibrary.value().uuid;
}
- RETURN_IF_ASTATUS_NOT_OK(getDescriptorWithUuid(lib.uuid, &desc),
+ RETURN_IF_ASTATUS_NOT_OK(getDescriptorWithUuid_l(lib.uuid, &desc),
"getDescriptorFailed");
process.ids.emplace_back(desc);
}
@@ -125,9 +128,10 @@
ndk::ScopedAStatus Factory::createEffect(const AudioUuid& in_impl_uuid,
std::shared_ptr<IEffect>* _aidl_return) {
LOG(DEBUG) << __func__ << ": UUID " << ::android::audio::utils::toString(in_impl_uuid);
+ std::lock_guard lg(mMutex);
if (mEffectLibMap.count(in_impl_uuid)) {
auto& entry = mEffectLibMap[in_impl_uuid];
- getDlSyms(entry);
+ getDlSyms_l(entry);
auto& libInterface = std::get<kMapEntryInterfaceIndex>(entry);
RETURN_IF(!libInterface || !libInterface->createEffectFunc, EX_NULL_POINTER,
@@ -152,7 +156,7 @@
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus Factory::destroyEffectImpl(const std::shared_ptr<IEffect>& in_handle) {
+ndk::ScopedAStatus Factory::destroyEffectImpl_l(const std::shared_ptr<IEffect>& in_handle) {
std::weak_ptr<IEffect> wpHandle(in_handle);
// find the effect entry with key (std::weak_ptr<IEffect>)
if (auto effectIt = mEffectMap.find(wpHandle); effectIt != mEffectMap.end()) {
@@ -177,7 +181,7 @@
}
// go over the map and cleanup all expired weak_ptrs.
-void Factory::cleanupEffectMap() {
+void Factory::cleanupEffectMap_l() {
for (auto it = mEffectMap.begin(); it != mEffectMap.end();) {
if (nullptr == it->first.lock()) {
it = mEffectMap.erase(it);
@@ -189,13 +193,15 @@
ndk::ScopedAStatus Factory::destroyEffect(const std::shared_ptr<IEffect>& in_handle) {
LOG(DEBUG) << __func__ << ": instance " << in_handle.get();
- ndk::ScopedAStatus status = destroyEffectImpl(in_handle);
+ std::lock_guard lg(mMutex);
+ ndk::ScopedAStatus status = destroyEffectImpl_l(in_handle);
// always do the cleanup
- cleanupEffectMap();
+ cleanupEffectMap_l();
return status;
}
-bool Factory::openEffectLibrary(const AudioUuid& impl, const std::string& path) {
+bool Factory::openEffectLibrary(const AudioUuid& impl,
+ const std::string& path) NO_THREAD_SAFETY_ANALYSIS {
std::function<void(void*)> dlClose = [](void* handle) -> void {
if (handle && dlclose(handle)) {
LOG(ERROR) << "dlclose failed " << dlerror();
@@ -219,9 +225,9 @@
return true;
}
-void Factory::createIdentityWithConfig(const EffectConfig::LibraryUuid& configLib,
- const AudioUuid& typeUuid,
- const std::optional<AudioUuid> proxyUuid) {
+void Factory::createIdentityWithConfig(
+ const EffectConfig::Library& configLib, const AudioUuid& typeUuid,
+ const std::optional<AudioUuid> proxyUuid) NO_THREAD_SAFETY_ANALYSIS {
static const auto& libMap = mConfig.getLibraryMap();
const std::string& libName = configLib.name;
if (auto path = libMap.find(libName); path != libMap.end()) {
@@ -246,8 +252,7 @@
void Factory::loadEffectLibs() {
const auto& configEffectsMap = mConfig.getEffectsMap();
for (const auto& configEffects : configEffectsMap) {
- if (AudioUuid uuid;
- EffectConfig::findUuid(configEffects.first /* xml effect name */, &uuid)) {
+ if (AudioUuid type; EffectConfig::findUuid(configEffects /* xml effect */, &type)) {
const auto& configLibs = configEffects.second;
std::optional<AudioUuid> proxyUuid;
if (configLibs.proxyLibrary.has_value()) {
@@ -255,7 +260,7 @@
proxyUuid = proxyLib.uuid;
}
for (const auto& configLib : configLibs.libraries) {
- createIdentityWithConfig(configLib, uuid, proxyUuid);
+ createIdentityWithConfig(configLib, type, proxyUuid);
}
} else {
LOG(ERROR) << __func__ << ": can not find type UUID for effect " << configEffects.first
@@ -264,7 +269,7 @@
}
}
-void Factory::getDlSyms(DlEntry& entry) {
+void Factory::getDlSyms_l(DlEntry& entry) {
auto& dlHandle = std::get<kMapEntryHandleIndex>(entry);
RETURN_VALUE_IF(!dlHandle, void(), "dlNullHandle");
// Get the reference of the DL interfaces in library map tuple.
diff --git a/audio/aidl/default/EffectImpl.cpp b/audio/aidl/default/EffectImpl.cpp
index da1ad11..c81c731 100644
--- a/audio/aidl/default/EffectImpl.cpp
+++ b/audio/aidl/default/EffectImpl.cpp
@@ -76,7 +76,7 @@
}
ndk::ScopedAStatus EffectImpl::setParameter(const Parameter& param) {
- LOG(DEBUG) << getEffectName() << __func__ << " with: " << param.toString();
+ LOG(VERBOSE) << getEffectName() << __func__ << " with: " << param.toString();
const auto tag = param.getTag();
switch (tag) {
@@ -100,7 +100,6 @@
}
ndk::ScopedAStatus EffectImpl::getParameter(const Parameter::Id& id, Parameter* param) {
- LOG(DEBUG) << getEffectName() << __func__ << id.toString();
auto tag = id.getTag();
switch (tag) {
case Parameter::Id::commonTag: {
@@ -117,7 +116,7 @@
break;
}
}
- LOG(DEBUG) << getEffectName() << __func__ << param->toString();
+ LOG(VERBOSE) << getEffectName() << __func__ << id.toString() << param->toString();
return ndk::ScopedAStatus::ok();
}
@@ -254,7 +253,7 @@
for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
- LOG(DEBUG) << getEffectName() << __func__ << " done processing " << samples << " samples";
+ LOG(VERBOSE) << getEffectName() << __func__ << " done processing " << samples << " samples";
return {STATUS_OK, samples, samples};
}
diff --git a/audio/aidl/default/EffectThread.cpp b/audio/aidl/default/EffectThread.cpp
index 574dc69..cd2ba53 100644
--- a/audio/aidl/default/EffectThread.cpp
+++ b/audio/aidl/default/EffectThread.cpp
@@ -149,8 +149,8 @@
IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples);
outputMQ->write(buffer, status.fmqProduced);
statusMQ->writeBlocking(&status, 1);
- LOG(DEBUG) << mName << __func__ << ": done processing, effect consumed "
- << status.fmqConsumed << " produced " << status.fmqProduced;
+ LOG(VERBOSE) << mName << __func__ << ": done processing, effect consumed "
+ << status.fmqConsumed << " produced " << status.fmqProduced;
}
}
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 48d1458..5478633 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -25,13 +25,12 @@
#include <android/binder_ibinder_platform.h>
#include <error/expected_utils.h>
-#include "core-impl/Bluetooth.h"
#include "core-impl/Module.h"
+#include "core-impl/ModulePrimary.h"
#include "core-impl/ModuleRemoteSubmix.h"
+#include "core-impl/ModuleStub.h"
#include "core-impl/ModuleUsb.h"
#include "core-impl/SoundDose.h"
-#include "core-impl/StreamStub.h"
-#include "core-impl/Telephony.h"
#include "core-impl/utils.h"
using aidl::android::hardware::audio::common::getFrameSizeInBytes;
@@ -110,13 +109,14 @@
// static
std::shared_ptr<Module> Module::createInstance(Type type) {
switch (type) {
- case Module::Type::USB:
- return ndk::SharedRefBase::make<ModuleUsb>(type);
- case Type::R_SUBMIX:
- return ndk::SharedRefBase::make<ModuleRemoteSubmix>(type);
case Type::DEFAULT:
- default:
- return ndk::SharedRefBase::make<Module>(type);
+ return ndk::SharedRefBase::make<ModulePrimary>();
+ case Type::R_SUBMIX:
+ return ndk::SharedRefBase::make<ModuleRemoteSubmix>();
+ case Type::STUB:
+ return ndk::SharedRefBase::make<ModuleStub>();
+ case Type::USB:
+ return ndk::SharedRefBase::make<ModuleUsb>();
}
}
@@ -128,6 +128,9 @@
case Module::Type::R_SUBMIX:
os << "r_submix";
break;
+ case Module::Type::STUB:
+ os << "stub";
+ break;
case Module::Type::USB:
os << "usb";
break;
@@ -283,19 +286,28 @@
return result;
}
+std::unique_ptr<internal::Configuration> Module::initializeConfig() {
+ std::unique_ptr<internal::Configuration> config;
+ switch (getType()) {
+ case Type::DEFAULT:
+ config = std::move(internal::getPrimaryConfiguration());
+ break;
+ case Type::R_SUBMIX:
+ config = std::move(internal::getRSubmixConfiguration());
+ break;
+ case Type::STUB:
+ config = std::move(internal::getStubConfiguration());
+ break;
+ case Type::USB:
+ config = std::move(internal::getUsbConfiguration());
+ break;
+ }
+ return config;
+}
+
internal::Configuration& Module::getConfig() {
if (!mConfig) {
- switch (mType) {
- case Type::DEFAULT:
- mConfig = std::move(internal::getPrimaryConfiguration());
- break;
- case Type::R_SUBMIX:
- mConfig = std::move(internal::getRSubmixConfiguration());
- break;
- case Type::USB:
- mConfig = std::move(internal::getUsbConfiguration());
- break;
- }
+ mConfig = std::move(initializeConfig());
}
return *mConfig;
}
@@ -395,38 +407,26 @@
}
ndk::ScopedAStatus Module::getTelephony(std::shared_ptr<ITelephony>* _aidl_return) {
- if (!mTelephony) {
- mTelephony = ndk::SharedRefBase::make<Telephony>();
- }
- *_aidl_return = mTelephony.getPtr();
- LOG(DEBUG) << __func__ << ": returning instance of ITelephony: " << _aidl_return->get();
+ *_aidl_return = nullptr;
+ LOG(DEBUG) << __func__ << ": returning null";
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Module::getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) {
- if (!mBluetooth) {
- mBluetooth = ndk::SharedRefBase::make<Bluetooth>();
- }
- *_aidl_return = mBluetooth.getPtr();
- LOG(DEBUG) << __func__ << ": returning instance of IBluetooth: " << _aidl_return->get();
+ *_aidl_return = nullptr;
+ LOG(DEBUG) << __func__ << ": returning null";
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Module::getBluetoothA2dp(std::shared_ptr<IBluetoothA2dp>* _aidl_return) {
- if (!mBluetoothA2dp) {
- mBluetoothA2dp = ndk::SharedRefBase::make<BluetoothA2dp>();
- }
- *_aidl_return = mBluetoothA2dp.getPtr();
- LOG(DEBUG) << __func__ << ": returning instance of IBluetoothA2dp: " << _aidl_return->get();
+ *_aidl_return = nullptr;
+ LOG(DEBUG) << __func__ << ": returning null";
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus Module::getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) {
- if (!mBluetoothLe) {
- mBluetoothLe = ndk::SharedRefBase::make<BluetoothLe>();
- }
- *_aidl_return = mBluetoothLe.getPtr();
- LOG(DEBUG) << __func__ << ": returning instance of IBluetoothLe: " << _aidl_return->get();
+ *_aidl_return = nullptr;
+ LOG(DEBUG) << __func__ << ": returning null";
return ndk::ScopedAStatus::ok();
}
@@ -1334,22 +1334,6 @@
return mIsMmapSupported.value();
}
-ndk::ScopedAStatus Module::createInputStream(const SinkMetadata& sinkMetadata,
- StreamContext&& context,
- const std::vector<MicrophoneInfo>& microphones,
- std::shared_ptr<StreamIn>* result) {
- return createStreamInstance<StreamInStub>(result, sinkMetadata, std::move(context),
- microphones);
-}
-
-ndk::ScopedAStatus Module::createOutputStream(const SourceMetadata& sourceMetadata,
- StreamContext&& context,
- const std::optional<AudioOffloadInfo>& offloadInfo,
- std::shared_ptr<StreamOut>* result) {
- return createStreamInstance<StreamOutStub>(result, sourceMetadata, std::move(context),
- offloadInfo);
-}
-
ndk::ScopedAStatus Module::populateConnectedDevicePort(AudioPort* audioPort __unused) {
LOG(VERBOSE) << __func__ << ": do nothing and return ok";
return ndk::ScopedAStatus::ok();
diff --git a/audio/aidl/default/ModulePrimary.cpp b/audio/aidl/default/ModulePrimary.cpp
new file mode 100644
index 0000000..cbb6730
--- /dev/null
+++ b/audio/aidl/default/ModulePrimary.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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 <vector>
+
+#define LOG_TAG "AHAL_ModulePrimary"
+#include <Utils.h>
+#include <android-base/logging.h>
+
+#include "core-impl/ModulePrimary.h"
+#include "core-impl/StreamStub.h"
+#include "core-impl/Telephony.h"
+
+using aidl::android::hardware::audio::common::SinkMetadata;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::media::audio::common::AudioOffloadInfo;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::MicrophoneInfo;
+
+namespace aidl::android::hardware::audio::core {
+
+ndk::ScopedAStatus ModulePrimary::getTelephony(std::shared_ptr<ITelephony>* _aidl_return) {
+ if (!mTelephony) {
+ mTelephony = ndk::SharedRefBase::make<Telephony>();
+ }
+ *_aidl_return = mTelephony.getPtr();
+ LOG(DEBUG) << __func__ << ": returning instance of ITelephony: " << _aidl_return->get();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModulePrimary::createInputStream(const SinkMetadata& sinkMetadata,
+ StreamContext&& context,
+ const std::vector<MicrophoneInfo>& microphones,
+ std::shared_ptr<StreamIn>* result) {
+ return createStreamInstance<StreamInStub>(result, sinkMetadata, std::move(context),
+ microphones);
+}
+
+ndk::ScopedAStatus ModulePrimary::createOutputStream(
+ const SourceMetadata& sourceMetadata, StreamContext&& context,
+ const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
+ return createStreamInstance<StreamOutStub>(result, sourceMetadata, std::move(context),
+ offloadInfo);
+}
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index 251dea0..215de94 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -110,10 +110,12 @@
if (isConnected) {
reply->observable.frames = mFrameCount;
reply->observable.timeNs = ::android::elapsedRealtimeNano();
- } else {
- reply->observable.frames = StreamDescriptor::Position::UNKNOWN;
- reply->observable.timeNs = StreamDescriptor::Position::UNKNOWN;
+ if (auto status = mDriver->getPosition(&reply->observable); status == ::android::OK) {
+ return;
+ }
}
+ reply->observable.frames = StreamDescriptor::Position::UNKNOWN;
+ reply->observable.timeNs = StreamDescriptor::Position::UNKNOWN;
}
void StreamWorkerCommonLogic::populateReplyWrongState(
diff --git a/audio/aidl/default/alsa/Mixer.cpp b/audio/aidl/default/alsa/Mixer.cpp
new file mode 100644
index 0000000..f0393e3
--- /dev/null
+++ b/audio/aidl/default/alsa/Mixer.cpp
@@ -0,0 +1,154 @@
+/*
+ * 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_AlsaMixer"
+#include <android-base/logging.h>
+
+#include <cmath>
+
+#include <android/binder_status.h>
+
+#include "Mixer.h"
+
+namespace aidl::android::hardware::audio::core::alsa {
+
+//-----------------------------------------------------------------------------
+
+MixerControl::MixerControl(struct mixer_ctl* ctl)
+ : mCtl(ctl),
+ mNumValues(mixer_ctl_get_num_values(ctl)),
+ mMinValue(mixer_ctl_get_range_min(ctl)),
+ mMaxValue(mixer_ctl_get_range_max(ctl)) {}
+
+unsigned int MixerControl::getNumValues() const {
+ return mNumValues;
+}
+
+int MixerControl::getMaxValue() const {
+ return mMaxValue;
+}
+
+int MixerControl::getMinValue() const {
+ return mMinValue;
+}
+
+int MixerControl::setArray(const void* array, size_t count) {
+ const std::lock_guard guard(mLock);
+ return mixer_ctl_set_array(mCtl, array, count);
+}
+
+//-----------------------------------------------------------------------------
+
+// static
+const std::map<Mixer::Control, std::vector<Mixer::ControlNamesAndExpectedCtlType>>
+ Mixer::kPossibleControls = {
+ {Mixer::MASTER_SWITCH, {{"Master Playback Switch", MIXER_CTL_TYPE_BOOL}}},
+ {Mixer::MASTER_VOLUME, {{"Master Playback Volume", MIXER_CTL_TYPE_INT}}},
+ {Mixer::HW_VOLUME,
+ {{"Headphone Playback Volume", MIXER_CTL_TYPE_INT},
+ {"Headset Playback Volume", MIXER_CTL_TYPE_INT},
+ {"PCM Playback Volume", MIXER_CTL_TYPE_INT}}}};
+
+// static
+std::map<Mixer::Control, std::shared_ptr<MixerControl>> Mixer::initializeMixerControls(
+ struct mixer* mixer) {
+ std::map<Mixer::Control, std::shared_ptr<MixerControl>> mixerControls;
+ std::string mixerCtlNames;
+ for (const auto& [control, possibleCtls] : kPossibleControls) {
+ for (const auto& [ctlName, expectedCtlType] : possibleCtls) {
+ struct mixer_ctl* ctl = mixer_get_ctl_by_name(mixer, ctlName.c_str());
+ if (ctl != nullptr && mixer_ctl_get_type(ctl) == expectedCtlType) {
+ mixerControls.emplace(control, std::make_unique<MixerControl>(ctl));
+ if (!mixerCtlNames.empty()) {
+ mixerCtlNames += ",";
+ }
+ mixerCtlNames += ctlName;
+ break;
+ }
+ }
+ }
+ LOG(DEBUG) << __func__ << ": available mixer control names=[" << mixerCtlNames << "]";
+ return mixerControls;
+}
+
+Mixer::Mixer(struct mixer* mixer)
+ : mMixer(mixer), mMixerControls(initializeMixerControls(mMixer)) {}
+
+Mixer::~Mixer() {
+ mixer_close(mMixer);
+}
+
+namespace {
+
+int volumeFloatToInteger(float fValue, int maxValue, int minValue) {
+ return minValue + std::ceil((maxValue - minValue) * fValue);
+}
+
+} // namespace
+
+ndk::ScopedAStatus Mixer::setMasterMute(bool muted) {
+ auto it = mMixerControls.find(Mixer::MASTER_SWITCH);
+ if (it == mMixerControls.end()) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+ const int numValues = it->second->getNumValues();
+ std::vector<int> values(numValues, muted ? 0 : 1);
+ if (int err = it->second->setArray(values.data(), numValues); err != 0) {
+ LOG(ERROR) << __func__ << ": failed to set master mute, err=" << err;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Mixer::setMasterVolume(float volume) {
+ auto it = mMixerControls.find(Mixer::MASTER_VOLUME);
+ if (it == mMixerControls.end()) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+ const int numValues = it->second->getNumValues();
+ std::vector<int> values(numValues, volumeFloatToInteger(volume, it->second->getMaxValue(),
+ it->second->getMinValue()));
+ if (int err = it->second->setArray(values.data(), numValues); err != 0) {
+ LOG(ERROR) << __func__ << ": failed to set master volume, err=" << err;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Mixer::setVolumes(const std::vector<float>& volumes) {
+ auto it = mMixerControls.find(Mixer::HW_VOLUME);
+ if (it == mMixerControls.end()) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+ const int numValues = it->second->getNumValues();
+ if (numValues < 0) {
+ LOG(FATAL) << __func__ << ": negative number of values: " << numValues;
+ }
+ const int maxValue = it->second->getMaxValue();
+ const int minValue = it->second->getMinValue();
+ std::vector<int> values;
+ size_t i = 0;
+ for (; i < static_cast<size_t>(numValues) && i < values.size(); ++i) {
+ values.emplace_back(volumeFloatToInteger(volumes[i], maxValue, minValue));
+ }
+ if (int err = it->second->setArray(values.data(), values.size()); err != 0) {
+ LOG(ERROR) << __func__ << ": failed to set volume, err=" << err;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+} // namespace aidl::android::hardware::audio::core::alsa
diff --git a/audio/aidl/default/alsa/Mixer.h b/audio/aidl/default/alsa/Mixer.h
new file mode 100644
index 0000000..de9e6f4
--- /dev/null
+++ b/audio/aidl/default/alsa/Mixer.h
@@ -0,0 +1,82 @@
+/*
+ * 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 <map>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <vector>
+
+#include <android-base/thread_annotations.h>
+#include <android/binder_auto_utils.h>
+
+extern "C" {
+#include <tinyalsa/mixer.h>
+}
+
+namespace aidl::android::hardware::audio::core::alsa {
+
+class MixerControl {
+ public:
+ explicit MixerControl(struct mixer_ctl* ctl);
+
+ unsigned int getNumValues() const;
+ int getMaxValue() const;
+ int getMinValue() const;
+ int setArray(const void* array, size_t count);
+
+ private:
+ std::mutex mLock;
+ // The mixer_ctl object is owned by ALSA and will be released when the mixer is closed.
+ struct mixer_ctl* mCtl GUARDED_BY(mLock);
+ const unsigned int mNumValues;
+ const int mMinValue;
+ const int mMaxValue;
+};
+
+class Mixer {
+ public:
+ explicit Mixer(struct mixer* mixer);
+
+ ~Mixer();
+
+ bool isValid() const { return mMixer != nullptr; }
+
+ ndk::ScopedAStatus setMasterMute(bool muted);
+ ndk::ScopedAStatus setMasterVolume(float volume);
+ ndk::ScopedAStatus setVolumes(const std::vector<float>& volumes);
+
+ private:
+ enum Control {
+ MASTER_SWITCH,
+ MASTER_VOLUME,
+ HW_VOLUME,
+ };
+ using ControlNamesAndExpectedCtlType = std::pair<std::string, enum mixer_ctl_type>;
+ static const std::map<Control, std::vector<ControlNamesAndExpectedCtlType>> kPossibleControls;
+ static std::map<Control, std::shared_ptr<MixerControl>> initializeMixerControls(
+ struct mixer* mixer);
+
+ // The mixer object is owned by ALSA and will be released when the mixer is closed.
+ struct mixer* mMixer;
+ // `mMixerControls` will only be initialized in constructor. After that, it wil only be
+ // read but not be modified.
+ const std::map<Control, std::shared_ptr<MixerControl>> mMixerControls;
+};
+
+} // namespace aidl::android::hardware::audio::core::alsa
diff --git a/audio/aidl/default/alsa/ModuleAlsa.cpp b/audio/aidl/default/alsa/ModuleAlsa.cpp
new file mode 100644
index 0000000..8e75d56
--- /dev/null
+++ b/audio/aidl/default/alsa/ModuleAlsa.cpp
@@ -0,0 +1,67 @@
+/*
+ * 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_ModuleAlsa"
+
+#include <vector>
+
+#include <android-base/logging.h>
+
+#include "Utils.h"
+#include "core-impl/ModuleAlsa.h"
+
+extern "C" {
+#include "alsa_device_profile.h"
+}
+
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioProfile;
+
+namespace aidl::android::hardware::audio::core {
+
+ndk::ScopedAStatus ModuleAlsa::populateConnectedDevicePort(AudioPort* audioPort) {
+ auto deviceProfile = alsa::getDeviceProfile(*audioPort);
+ if (!deviceProfile.has_value()) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ auto profile = alsa::readAlsaDeviceInfo(*deviceProfile);
+ if (!profile.has_value()) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+
+ std::vector<AudioChannelLayout> channels = alsa::getChannelMasksFromProfile(&profile.value());
+ std::vector<int> sampleRates = alsa::getSampleRatesFromProfile(&profile.value());
+
+ for (size_t i = 0; i < std::min(MAX_PROFILE_FORMATS, AUDIO_PORT_MAX_AUDIO_PROFILES) &&
+ profile->formats[i] != PCM_FORMAT_INVALID;
+ ++i) {
+ auto audioFormatDescription =
+ alsa::c2aidl_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();
+}
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/alsa/StreamAlsa.cpp b/audio/aidl/default/alsa/StreamAlsa.cpp
new file mode 100644
index 0000000..17c7feb
--- /dev/null
+++ b/audio/aidl/default/alsa/StreamAlsa.cpp
@@ -0,0 +1,135 @@
+/*
+ * 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 <limits>
+
+#define LOG_TAG "AHAL_StreamAlsa"
+#include <android-base/logging.h>
+
+#include <Utils.h>
+#include <audio_utils/clock.h>
+#include <error/expected_utils.h>
+
+#include "core-impl/StreamAlsa.h"
+
+namespace aidl::android::hardware::audio::core {
+
+StreamAlsa::StreamAlsa(const Metadata& metadata, StreamContext&& context)
+ : StreamCommonImpl(metadata, std::move(context)),
+ mFrameSizeBytes(getContext().getFrameSize()),
+ mIsInput(isInput(metadata)),
+ mConfig(alsa::getPcmConfig(getContext(), mIsInput)) {}
+
+::android::status_t StreamAlsa::init() {
+ return mConfig.has_value() ? ::android::OK : ::android::NO_INIT;
+}
+
+::android::status_t StreamAlsa::standby() {
+ mAlsaDeviceProxies.clear();
+ return ::android::OK;
+}
+
+::android::status_t StreamAlsa::start() {
+ decltype(mAlsaDeviceProxies) alsaDeviceProxies;
+ for (const auto& device : getDeviceProfiles()) {
+ auto profile = alsa::readAlsaDeviceInfo(device);
+ if (!profile.has_value()) {
+ LOG(ERROR) << __func__ << ": unable to read device info, device address=" << device;
+ return ::android::UNKNOWN_ERROR;
+ }
+
+ auto proxy = alsa::makeDeviceProxy();
+ // 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.value(),
+ const_cast<struct pcm_config*>(&mConfig.value()),
+ true /*require_exact_match*/);
+ err != 0) {
+ LOG(ERROR) << __func__ << ": fail to prepare for device address=" << device
+ << " error=" << err;
+ return ::android::UNKNOWN_ERROR;
+ }
+ if (int err = proxy_open(proxy.get()); err != 0) {
+ LOG(ERROR) << __func__ << ": failed to open device, address=" << device
+ << " error=" << err;
+ return ::android::UNKNOWN_ERROR;
+ }
+ alsaDeviceProxies.push_back(std::move(proxy));
+ }
+ mAlsaDeviceProxies = std::move(alsaDeviceProxies);
+ return ::android::OK;
+}
+
+::android::status_t StreamAlsa::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
+ int32_t* latencyMs) {
+ const size_t bytesToTransfer = frameCount * mFrameSizeBytes;
+ unsigned maxLatency = 0;
+ if (mIsInput) {
+ if (mAlsaDeviceProxies.empty()) {
+ LOG(FATAL) << __func__ << ": no input devices";
+ return ::android::NO_INIT;
+ }
+ // For input case, only support single device.
+ proxy_read(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer);
+ maxLatency = proxy_get_latency(mAlsaDeviceProxies[0].get());
+ } else {
+ for (auto& proxy : mAlsaDeviceProxies) {
+ proxy_write(proxy.get(), buffer, bytesToTransfer);
+ maxLatency = std::max(maxLatency, proxy_get_latency(proxy.get()));
+ }
+ }
+ *actualFrameCount = frameCount;
+ maxLatency = std::min(maxLatency, static_cast<unsigned>(std::numeric_limits<int32_t>::max()));
+ *latencyMs = maxLatency;
+ return ::android::OK;
+}
+
+::android::status_t StreamAlsa::getPosition(StreamDescriptor::Position* position) {
+ if (mAlsaDeviceProxies.empty()) {
+ LOG(FATAL) << __func__ << ": no input devices";
+ return ::android::NO_INIT;
+ }
+ if (mIsInput) {
+ if (int ret = proxy_get_capture_position(mAlsaDeviceProxies[0].get(), &position->frames,
+ &position->timeNs);
+ ret != 0) {
+ LOG(WARNING) << __func__ << ": failed to retrieve capture position: " << ret;
+ return ::android::INVALID_OPERATION;
+ }
+ } else {
+ uint64_t hwFrames;
+ struct timespec timestamp;
+ if (int ret = proxy_get_presentation_position(mAlsaDeviceProxies[0].get(), &hwFrames,
+ ×tamp);
+ ret == 0) {
+ if (hwFrames > std::numeric_limits<int64_t>::max()) {
+ hwFrames -= std::numeric_limits<int64_t>::max();
+ }
+ position->frames = static_cast<int64_t>(hwFrames);
+ position->timeNs = audio_utils_ns_from_timespec(×tamp);
+ } else {
+ LOG(WARNING) << __func__ << ": failed to retrieve presentation position: " << ret;
+ return ::android::INVALID_OPERATION;
+ }
+ }
+ return ::android::OK;
+}
+
+void StreamAlsa::shutdown() {
+ mAlsaDeviceProxies.clear();
+}
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/alsa/Utils.cpp b/audio/aidl/default/alsa/Utils.cpp
new file mode 100644
index 0000000..162f852
--- /dev/null
+++ b/audio/aidl/default/alsa/Utils.cpp
@@ -0,0 +1,293 @@
+/*
+ * 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>
+
+#define LOG_TAG "AHAL_AlsaUtils"
+#include <Utils.h>
+#include <aidl/android/media/audio/common/AudioFormatType.h>
+#include <aidl/android/media/audio/common/PcmType.h>
+#include <android-base/logging.h>
+
+#include "Utils.h"
+#include "core-impl/utils.h"
+
+using aidl::android::hardware::audio::common::getChannelCount;
+using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+using aidl::android::media::audio::common::AudioFormatDescription;
+using aidl::android::media::audio::common::AudioFormatType;
+using aidl::android::media::audio::common::AudioIoFlags;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::PcmType;
+
+namespace aidl::android::hardware::audio::core::alsa {
+
+namespace {
+
+using AudioChannelCountToMaskMap = std::map<unsigned int, AudioChannelLayout>;
+using AudioFormatDescToPcmFormatMap = std::map<AudioFormatDescription, enum pcm_format>;
+using PcmFormatToAudioFormatDescMap = std::map<enum pcm_format, AudioFormatDescription>;
+
+AudioChannelLayout getInvalidChannelLayout() {
+ static const AudioChannelLayout invalidChannelLayout =
+ AudioChannelLayout::make<AudioChannelLayout::Tag::invalid>(0);
+ return invalidChannelLayout;
+}
+
+static AudioChannelCountToMaskMap make_ChannelCountToMaskMap(
+ const std::set<AudioChannelLayout>& channelMasks) {
+ AudioChannelCountToMaskMap channelMaskToCountMap;
+ for (const auto& channelMask : channelMasks) {
+ channelMaskToCountMap.emplace(getChannelCount(channelMask), channelMask);
+ }
+ return channelMaskToCountMap;
+}
+
+#define DEFINE_CHANNEL_LAYOUT_MASK(n) \
+ AudioChannelLayout::make<AudioChannelLayout::Tag::layoutMask>(AudioChannelLayout::LAYOUT_##n)
+
+const AudioChannelCountToMaskMap& getSupportedChannelOutLayoutMap() {
+ static const std::set<AudioChannelLayout> supportedOutChannelLayouts = {
+ 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 AudioChannelCountToMaskMap outLayouts =
+ make_ChannelCountToMaskMap(supportedOutChannelLayouts);
+ return outLayouts;
+}
+
+const AudioChannelCountToMaskMap& getSupportedChannelInLayoutMap() {
+ static const std::set<AudioChannelLayout> supportedInChannelLayouts = {
+ DEFINE_CHANNEL_LAYOUT_MASK(MONO),
+ DEFINE_CHANNEL_LAYOUT_MASK(STEREO),
+ };
+ static const AudioChannelCountToMaskMap inLayouts =
+ make_ChannelCountToMaskMap(supportedInChannelLayouts);
+ return inLayouts;
+}
+
+#undef DEFINE_CHANNEL_LAYOUT_MASK
+#define DEFINE_CHANNEL_INDEX_MASK(n) \
+ AudioChannelLayout::make<AudioChannelLayout::Tag::indexMask>(AudioChannelLayout::INDEX_MASK_##n)
+
+const AudioChannelCountToMaskMap& getSupportedChannelIndexLayoutMap() {
+ static const std::set<AudioChannelLayout> supportedIndexChannelLayouts = {
+ 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 const AudioChannelCountToMaskMap indexLayouts =
+ make_ChannelCountToMaskMap(supportedIndexChannelLayouts);
+ return indexLayouts;
+}
+
+#undef DEFINE_CHANNEL_INDEX_MASK
+
+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::FIXED_Q_8_24), PCM_FORMAT_S24_LE},
+ {make_AudioFormatDescription(PcmType::INT_24_BIT), 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
+
+std::ostream& operator<<(std::ostream& os, const DeviceProfile& device) {
+ return os << "<" << device.card << "," << device.device << ">";
+}
+
+AudioChannelLayout getChannelLayoutMaskFromChannelCount(unsigned int channelCount, int isInput) {
+ return findValueOrDefault(
+ isInput ? getSupportedChannelInLayoutMap() : getSupportedChannelOutLayoutMap(),
+ channelCount, getInvalidChannelLayout());
+}
+
+AudioChannelLayout getChannelIndexMaskFromChannelCount(unsigned int channelCount) {
+ return findValueOrDefault(getSupportedChannelIndexLayoutMap(), channelCount,
+ getInvalidChannelLayout());
+}
+
+unsigned int getChannelCountFromChannelMask(const AudioChannelLayout& channelMask, bool isInput) {
+ switch (channelMask.getTag()) {
+ case AudioChannelLayout::Tag::layoutMask: {
+ return findKeyOrDefault(
+ isInput ? getSupportedChannelInLayoutMap() : getSupportedChannelOutLayoutMap(),
+ static_cast<unsigned>(getChannelCount(channelMask)), 0u /*defaultValue*/);
+ }
+ case AudioChannelLayout::Tag::indexMask: {
+ return findKeyOrDefault(getSupportedChannelIndexLayoutMap(),
+ static_cast<unsigned>(getChannelCount(channelMask)),
+ 0u /*defaultValue*/);
+ }
+ case AudioChannelLayout::Tag::none:
+ case AudioChannelLayout::Tag::invalid:
+ case AudioChannelLayout::Tag::voiceMask:
+ default:
+ return 0;
+ }
+}
+
+std::vector<AudioChannelLayout> getChannelMasksFromProfile(const alsa_device_profile* profile) {
+ const bool isInput = profile->direction == PCM_IN;
+ std::vector<AudioChannelLayout> channels;
+ for (size_t i = 0; i < AUDIO_PORT_MAX_CHANNEL_MASKS && profile->channel_counts[i] != 0; ++i) {
+ auto layoutMask =
+ alsa::getChannelLayoutMaskFromChannelCount(profile->channel_counts[i], isInput);
+ if (layoutMask.getTag() == AudioChannelLayout::Tag::layoutMask) {
+ channels.push_back(layoutMask);
+ }
+ auto indexMask = alsa::getChannelIndexMaskFromChannelCount(profile->channel_counts[i]);
+ if (indexMask.getTag() == AudioChannelLayout::Tag::indexMask) {
+ channels.push_back(indexMask);
+ }
+ }
+ return channels;
+}
+
+std::optional<DeviceProfile> getDeviceProfile(
+ const ::aidl::android::media::audio::common::AudioDevice& audioDevice, bool isInput) {
+ if (audioDevice.address.getTag() != AudioDeviceAddress::Tag::alsa) {
+ LOG(ERROR) << __func__ << ": not alsa address: " << audioDevice.toString();
+ return std::nullopt;
+ }
+ auto& alsaAddress = audioDevice.address.get<AudioDeviceAddress::Tag::alsa>();
+ if (alsaAddress.size() != 2 || alsaAddress[0] < 0 || alsaAddress[1] < 0) {
+ LOG(ERROR) << __func__
+ << ": malformed alsa address: " << ::android::internal::ToString(alsaAddress);
+ return std::nullopt;
+ }
+ return DeviceProfile{.card = alsaAddress[0],
+ .device = alsaAddress[1],
+ .direction = isInput ? PCM_IN : PCM_OUT};
+}
+
+std::optional<DeviceProfile> getDeviceProfile(
+ const ::aidl::android::media::audio::common::AudioPort& audioPort) {
+ if (audioPort.ext.getTag() != AudioPortExt::Tag::device) {
+ LOG(ERROR) << __func__ << ": port id " << audioPort.id << " is not a device port";
+ return std::nullopt;
+ }
+ auto& devicePort = audioPort.ext.get<AudioPortExt::Tag::device>();
+ return getDeviceProfile(devicePort.device, audioPort.flags.getTag() == AudioIoFlags::input);
+}
+
+std::optional<struct pcm_config> getPcmConfig(const StreamContext& context, bool isInput) {
+ struct pcm_config config;
+ config.channels = alsa::getChannelCountFromChannelMask(context.getChannelLayout(), isInput);
+ if (config.channels == 0) {
+ LOG(ERROR) << __func__ << ": invalid channel=" << context.getChannelLayout().toString();
+ return std::nullopt;
+ }
+ config.format = alsa::aidl2c_AudioFormatDescription_pcm_format(context.getFormat());
+ if (config.format == PCM_FORMAT_INVALID) {
+ LOG(ERROR) << __func__ << ": invalid format=" << context.getFormat().toString();
+ return std::nullopt;
+ }
+ config.rate = context.getSampleRate();
+ if (config.rate == 0) {
+ LOG(ERROR) << __func__ << ": invalid sample rate=" << config.rate;
+ return std::nullopt;
+ }
+ return config;
+}
+
+std::vector<int> getSampleRatesFromProfile(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;
+}
+
+DeviceProxy makeDeviceProxy() {
+ return DeviceProxy(new alsa_device_proxy, [](alsa_device_proxy* proxy) {
+ if (proxy != nullptr) {
+ proxy_close(proxy);
+ delete proxy;
+ }
+ });
+}
+
+std::optional<alsa_device_profile> readAlsaDeviceInfo(const DeviceProfile& deviceProfile) {
+ alsa_device_profile profile;
+ profile_init(&profile, deviceProfile.direction);
+ profile.card = deviceProfile.card;
+ profile.device = deviceProfile.device;
+ if (!profile_read_device_info(&profile)) {
+ LOG(ERROR) << __func__ << ": failed to read device info, card=" << profile.card
+ << ", device=" << profile.device;
+ return std::nullopt;
+ }
+ return profile;
+}
+
+AudioFormatDescription c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy) {
+ return findValueOrDefault(getPcmFormatToAudioFormatDescMap(), legacy, AudioFormatDescription());
+}
+
+pcm_format aidl2c_AudioFormatDescription_pcm_format(const AudioFormatDescription& aidl) {
+ return findValueOrDefault(getAudioFormatDescriptorToPcmFormatMap(), aidl, PCM_FORMAT_INVALID);
+}
+
+} // namespace aidl::android::hardware::audio::core::alsa
diff --git a/audio/aidl/default/alsa/Utils.h b/audio/aidl/default/alsa/Utils.h
new file mode 100644
index 0000000..c1b9b38
--- /dev/null
+++ b/audio/aidl/default/alsa/Utils.h
@@ -0,0 +1,70 @@
+/*
+ * 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 <functional>
+#include <iostream>
+#include <memory>
+#include <optional>
+#include <vector>
+
+#include <aidl/android/media/audio/common/AudioChannelLayout.h>
+#include <aidl/android/media/audio/common/AudioFormatDescription.h>
+#include <aidl/android/media/audio/common/AudioPort.h>
+
+#include "core-impl/Stream.h"
+
+extern "C" {
+#include <tinyalsa/pcm.h>
+#include "alsa_device_profile.h"
+#include "alsa_device_proxy.h"
+}
+
+namespace aidl::android::hardware::audio::core::alsa {
+
+struct DeviceProfile {
+ int card;
+ int device;
+ int direction; /* PCM_OUT or PCM_IN */
+};
+std::ostream& operator<<(std::ostream& os, const DeviceProfile& device);
+using DeviceProxyDeleter = std::function<void(alsa_device_proxy*)>;
+using DeviceProxy = std::unique_ptr<alsa_device_proxy, DeviceProxyDeleter>;
+
+::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);
+std::vector<::aidl::android::media::audio::common::AudioChannelLayout> getChannelMasksFromProfile(
+ const alsa_device_profile* profile);
+std::optional<DeviceProfile> getDeviceProfile(
+ const ::aidl::android::media::audio::common::AudioDevice& audioDevice, bool isInput);
+std::optional<DeviceProfile> getDeviceProfile(
+ const ::aidl::android::media::audio::common::AudioPort& audioPort);
+std::optional<struct pcm_config> getPcmConfig(const StreamContext& context, bool isInput);
+std::vector<int> getSampleRatesFromProfile(const alsa_device_profile* profile);
+DeviceProxy makeDeviceProxy();
+std::optional<alsa_device_profile> readAlsaDeviceInfo(const DeviceProfile& deviceProfile);
+
+::aidl::android::media::audio::common::AudioFormatDescription
+c2aidl_pcm_format_AudioFormatDescription(enum pcm_format legacy);
+pcm_format aidl2c_AudioFormatDescription_pcm_format(
+ const ::aidl::android::media::audio::common::AudioFormatDescription& aidl);
+
+} // namespace aidl::android::hardware::audio::core::alsa
diff --git a/audio/aidl/default/android.hardware.audio.service-aidl.xml b/audio/aidl/default/android.hardware.audio.service-aidl.xml
index 9636a58..c9d6314 100644
--- a/audio/aidl/default/android.hardware.audio.service-aidl.xml
+++ b/audio/aidl/default/android.hardware.audio.service-aidl.xml
@@ -12,6 +12,11 @@
<hal format="aidl">
<name>android.hardware.audio.core</name>
<version>1</version>
+ <fqname>IModule/stub</fqname>
+ </hal>
+ <hal format="aidl">
+ <name>android.hardware.audio.core</name>
+ <version>1</version>
<fqname>IModule/usb</fqname>
</hal>
<hal format="aidl">
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
index 6627ae7..00de797 100644
--- a/audio/aidl/default/audio_effects_config.xml
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -50,7 +50,8 @@
</libraries>
<!-- list of effects to load.
- Each "effect" element must contain a "name", "library" and a "uuid" attribute.
+ Each "effect" element must contain a "name", "library" and a "uuid" attribute, an optional
+ "type" attribute can be used to add any customized effect type.
The value of the "library" attribute must correspond to the name of one library element in
the "libraries" element.
The "name" attribute used to specific effect type, and should be mapping to a key of
@@ -62,8 +63,8 @@
result of IFactory.queryEffects() to decide which effect implementation should be part of
proxy and which not.
- Only "name", "library", and "uuid" attributes in "effects" element are meaningful and
- parsed out by EffectConfig class, all other attributes are ignored.
+ Only "name", "library", "uuid", and "type" attributes in "effects" element are meaningful
+ and parsed out by EffectConfig class, all other attributes are ignored.
Only "name" and "uuid" attributes in "effectProxy" element are meaningful and parsed out
by EffectConfig class, all other attributes are ignored.
-->
@@ -94,7 +95,7 @@
<libsw library="equalizersw" uuid="0bed4300-847d-11df-bb17-0002a5d5c51b"/>
<libsw library="bundle" uuid="ce772f20-847d-11df-bb17-0002a5d5c51b"/>
</effectProxy>
- <effect name="extensioneffect" library="extensioneffect" uuid="fa81dd00-588b-11ed-9b6a-0242ac120002"/>
+ <effect name="extension_effect" library="extensioneffect" uuid="fa81dd00-588b-11ed-9b6a-0242ac120002" type="fa81de0e-588b-11ed-9b6a-0242ac120002"/>
<effect name="acoustic_echo_canceler" library="aecsw" uuid="bb392ec0-8d4d-11e0-a896-0002a5d5c51b"/>
<effect name="noise_suppression" library="nssw" uuid="c06c8400-8e06-11e0-9cb6-0002a5d5c51b"/>
</effects>
diff --git a/audio/aidl/default/include/core-impl/ChildInterface.h b/audio/aidl/default/include/core-impl/ChildInterface.h
new file mode 100644
index 0000000..1b31691
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/ChildInterface.h
@@ -0,0 +1,48 @@
+/*
+ * 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 <memory>
+#include <utility>
+
+#include <android/binder_auto_utils.h>
+#include <android/binder_ibinder_platform.h>
+#include <system/thread_defs.h>
+
+namespace aidl::android::hardware::audio::core {
+
+// Helper used for interfaces that require a persistent instance. We hold them via a strong
+// pointer. The binder token is retained for a call to 'setMinSchedulerPolicy'.
+template <class C>
+struct ChildInterface : private std::pair<std::shared_ptr<C>, ndk::SpAIBinder> {
+ ChildInterface() = default;
+ ChildInterface& operator=(const std::shared_ptr<C>& c) {
+ return operator=(std::shared_ptr<C>(c));
+ }
+ ChildInterface& operator=(std::shared_ptr<C>&& c) {
+ this->first = std::move(c);
+ this->second = this->first->asBinder();
+ AIBinder_setMinSchedulerPolicy(this->second.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
+ return *this;
+ }
+ explicit operator bool() const { return !!this->first; }
+ C& operator*() const { return *(this->first); }
+ C* operator->() const { return this->first; }
+ std::shared_ptr<C> getPtr() const { return this->first; }
+};
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/Configuration.h b/audio/aidl/default/include/core-impl/Configuration.h
index 70320e4..25bf7af 100644
--- a/audio/aidl/default/include/core-impl/Configuration.h
+++ b/audio/aidl/default/include/core-impl/Configuration.h
@@ -45,6 +45,7 @@
std::unique_ptr<Configuration> getPrimaryConfiguration();
std::unique_ptr<Configuration> getRSubmixConfiguration();
+std::unique_ptr<Configuration> getStubConfiguration();
std::unique_ptr<Configuration> getUsbConfiguration();
} // namespace aidl::android::hardware::audio::core::internal
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index 4a23637..294cc0e 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -16,12 +16,14 @@
#pragma once
+#include <iostream>
#include <map>
#include <memory>
#include <set>
#include <aidl/android/hardware/audio/core/BnModule.h>
+#include "core-impl/ChildInterface.h"
#include "core-impl/Configuration.h"
#include "core-impl/Stream.h"
@@ -31,7 +33,7 @@
public:
// This value is used for all AudioPatches and reported by all streams.
static constexpr int32_t kLatencyMs = 10;
- enum Type : int { DEFAULT, R_SUBMIX, USB };
+ enum Type : int { DEFAULT, R_SUBMIX, STUB, USB };
static std::shared_ptr<Module> createInstance(Type type);
@@ -132,26 +134,6 @@
bool forceTransientBurst = false;
bool forceSynchronousDrain = false;
};
- // Helper used for interfaces that require a persistent instance. We hold them via a strong
- // pointer. The binder token is retained for a call to 'setMinSchedulerPolicy'.
- template <class C>
- struct ChildInterface : private std::pair<std::shared_ptr<C>, ndk::SpAIBinder> {
- ChildInterface() {}
- ChildInterface& operator=(const std::shared_ptr<C>& c) {
- return operator=(std::shared_ptr<C>(c));
- }
- ChildInterface& operator=(std::shared_ptr<C>&& c) {
- this->first = std::move(c);
- this->second = this->first->asBinder();
- AIBinder_setMinSchedulerPolicy(this->second.get(), SCHED_NORMAL,
- ANDROID_PRIORITY_AUDIO);
- return *this;
- }
- explicit operator bool() const { return !!this->first; }
- C& operator*() const { return *(this->first); }
- C* operator->() const { return this->first; }
- std::shared_ptr<C> getPtr() const { return this->first; }
- };
// ids of device ports created at runtime via 'connectExternalDevice'.
// Also stores a list of ids of mix ports with dynamic profiles that were populated from
// the connected port. This list can be empty, thus an int->int multimap can't be used.
@@ -164,10 +146,6 @@
std::unique_ptr<internal::Configuration> mConfig;
ModuleDebug mDebug;
VendorDebug mVendorDebug;
- ChildInterface<ITelephony> mTelephony;
- ChildInterface<IBluetooth> mBluetooth;
- ChildInterface<IBluetoothA2dp> mBluetoothA2dp;
- ChildInterface<IBluetoothLe> mBluetoothLe;
ConnectedDevicePorts mConnectedDevicePorts;
Streams mStreams;
Patches mPatches;
@@ -184,13 +162,13 @@
const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
StreamContext&& context,
const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
- std::shared_ptr<StreamIn>* result);
+ std::shared_ptr<StreamIn>* result) = 0;
virtual ndk::ScopedAStatus createOutputStream(
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);
+ std::shared_ptr<StreamOut>* result) = 0;
// 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(
@@ -204,6 +182,7 @@
const ::aidl::android::media::audio::common::AudioPort& audioPort, bool connected);
virtual ndk::ScopedAStatus onMasterMuteChanged(bool mute);
virtual ndk::ScopedAStatus onMasterVolumeChanged(float volume);
+ virtual std::unique_ptr<internal::Configuration> initializeConfig();
// Utility and helper functions accessible to subclasses.
void cleanUpPatch(int32_t patchId);
@@ -224,6 +203,7 @@
bool getMicMute() const { return mMicMute; }
const Patches& getPatches() const { return mPatches; }
const Streams& getStreams() const { return mStreams; }
+ Type getType() const { return mType; }
bool isMmapSupported();
template <typename C>
std::set<int32_t> portIdsFromPortConfigIds(C portConfigIds);
@@ -232,4 +212,6 @@
const AudioPatch& newPatch);
};
+std::ostream& operator<<(std::ostream& os, Module::Type t);
+
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/ModuleAlsa.h b/audio/aidl/default/include/core-impl/ModuleAlsa.h
new file mode 100644
index 0000000..5815961
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/ModuleAlsa.h
@@ -0,0 +1,38 @@
+/*
+ * 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 {
+
+// This class is intended to be used as a base class for implementations
+// that use TinyAlsa. This can be either a primary module or a USB Audio
+// module. This class does not define a complete module implementation,
+// and should never be used on its own. Derived classes are expected to
+// provide necessary overrides for all interface methods omitted here.
+class ModuleAlsa : public Module {
+ public:
+ explicit ModuleAlsa(Module::Type type) : Module(type) {}
+
+ protected:
+ // Extension methods of 'Module'.
+ ndk::ScopedAStatus populateConnectedDevicePort(
+ ::aidl::android::media::audio::common::AudioPort* audioPort) override;
+};
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/ModulePrimary.h b/audio/aidl/default/include/core-impl/ModulePrimary.h
new file mode 100644
index 0000000..bc808ab
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/ModulePrimary.h
@@ -0,0 +1,46 @@
+/*
+ * 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 ModulePrimary final : public Module {
+ public:
+ ModulePrimary() : Module(Type::DEFAULT) {}
+
+ protected:
+ ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override;
+
+ ndk::ScopedAStatus createInputStream(
+ const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
+ StreamContext&& context,
+ const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
+ std::shared_ptr<StreamIn>* result) override;
+ ndk::ScopedAStatus createOutputStream(
+ 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) override;
+
+ private:
+ ChildInterface<ITelephony> mTelephony;
+};
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h b/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h
index 7b1d375..ccfcdd9 100644
--- a/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h
+++ b/audio/aidl/default/include/core-impl/ModuleRemoteSubmix.h
@@ -22,7 +22,7 @@
class ModuleRemoteSubmix : public Module {
public:
- explicit ModuleRemoteSubmix(Module::Type type) : Module(type) {}
+ ModuleRemoteSubmix() : Module(Type::R_SUBMIX) {}
private:
// IModule interfaces
diff --git a/audio/aidl/default/include/core-impl/ModuleStub.h b/audio/aidl/default/include/core-impl/ModuleStub.h
new file mode 100644
index 0000000..59c343f
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/ModuleStub.h
@@ -0,0 +1,50 @@
+/*
+ * 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 ModuleStub final : public Module {
+ public:
+ ModuleStub() : Module(Type::STUB) {}
+
+ protected:
+ ndk::ScopedAStatus getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) override;
+ ndk::ScopedAStatus getBluetoothA2dp(std::shared_ptr<IBluetoothA2dp>* _aidl_return) override;
+ ndk::ScopedAStatus getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) override;
+
+ ndk::ScopedAStatus createInputStream(
+ const ::aidl::android::hardware::audio::common::SinkMetadata& sinkMetadata,
+ StreamContext&& context,
+ const std::vector<::aidl::android::media::audio::common::MicrophoneInfo>& microphones,
+ std::shared_ptr<StreamIn>* result) override;
+ ndk::ScopedAStatus createOutputStream(
+ 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) override;
+
+ private:
+ ChildInterface<IBluetooth> mBluetooth;
+ ChildInterface<IBluetoothA2dp> mBluetoothA2dp;
+ ChildInterface<IBluetoothLe> mBluetoothLe;
+};
+
+} // 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
index 5a5429d..e6b3e66 100644
--- a/audio/aidl/default/include/core-impl/ModuleUsb.h
+++ b/audio/aidl/default/include/core-impl/ModuleUsb.h
@@ -16,13 +16,13 @@
#pragma once
-#include "core-impl/Module.h"
+#include "core-impl/ModuleAlsa.h"
namespace aidl::android::hardware::audio::core {
-class ModuleUsb : public Module {
+class ModuleUsb final : public ModuleAlsa {
public:
- explicit ModuleUsb(Module::Type type) : Module(type) {}
+ ModuleUsb() : ModuleAlsa(Type::USB) {}
private:
// IModule interfaces
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index aaf5860..e64c578 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -184,6 +184,12 @@
virtual ::android::status_t start() = 0;
virtual ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
int32_t* latencyMs) = 0;
+ // No need to implement 'getPosition' unless the driver can provide more precise
+ // data than just total frame count. For example, the driver may correctly account
+ // for any intermediate buffers.
+ virtual ::android::status_t getPosition(StreamDescriptor::Position* /*position*/) {
+ return ::android::OK;
+ }
virtual void shutdown() = 0; // This function is only called once.
};
diff --git a/audio/aidl/default/include/core-impl/StreamAlsa.h b/audio/aidl/default/include/core-impl/StreamAlsa.h
new file mode 100644
index 0000000..5744d66
--- /dev/null
+++ b/audio/aidl/default/include/core-impl/StreamAlsa.h
@@ -0,0 +1,55 @@
+/*
+ * 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 <optional>
+#include <vector>
+
+#include "Stream.h"
+#include "alsa/Utils.h"
+
+namespace aidl::android::hardware::audio::core {
+
+// This class is intended to be used as a base class for implementations
+// that use TinyAlsa.
+// This class does not define a complete stream implementation,
+// and should never be used on its own. Derived classes are expected to
+// provide necessary overrides for all interface methods omitted here.
+class StreamAlsa : public StreamCommonImpl {
+ public:
+ StreamAlsa(const Metadata& metadata, StreamContext&& context);
+ // Methods of 'DriverInterface'.
+ ::android::status_t init() override;
+ ::android::status_t standby() override;
+ ::android::status_t start() override;
+ ::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
+ int32_t* latencyMs) override;
+ ::android::status_t getPosition(StreamDescriptor::Position* position) override;
+ void shutdown() override;
+
+ protected:
+ // Called from 'start' to initialize 'mAlsaDeviceProxies', the vector must be non-empty.
+ virtual std::vector<alsa::DeviceProfile> getDeviceProfiles() = 0;
+
+ const size_t mFrameSizeBytes;
+ const bool mIsInput;
+ const std::optional<struct pcm_config> mConfig;
+ // All fields below are only used on the worker thread.
+ std::vector<alsa::DeviceProxy> mAlsaDeviceProxies;
+};
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
index 2253ec7..1bca910 100644
--- a/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
+++ b/audio/aidl/default/include/core-impl/StreamRemoteSubmix.h
@@ -39,6 +39,7 @@
::android::status_t start() override;
::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
int32_t* latencyMs) override;
+ ::android::status_t getPosition(StreamDescriptor::Position* position) override;
void shutdown() override;
// Overridden methods of 'StreamCommonImpl', called on a Binder thread.
diff --git a/audio/aidl/default/include/core-impl/StreamUsb.h b/audio/aidl/default/include/core-impl/StreamUsb.h
index 8c40782..44f742a 100644
--- a/audio/aidl/default/include/core-impl/StreamUsb.h
+++ b/audio/aidl/default/include/core-impl/StreamUsb.h
@@ -17,55 +17,34 @@
#pragma once
#include <atomic>
-#include <functional>
#include <mutex>
-#include <optional>
#include <vector>
#include <aidl/android/media/audio/common/AudioChannelLayout.h>
-#include "core-impl/Stream.h"
-
-extern "C" {
-#include <tinyalsa/pcm.h>
-#include "alsa_device_proxy.h"
-}
+#include "StreamAlsa.h"
namespace aidl::android::hardware::audio::core {
-class StreamUsb : public StreamCommonImpl {
+class StreamUsb : public StreamAlsa {
public:
StreamUsb(const Metadata& metadata, StreamContext&& context);
// Methods of 'DriverInterface'.
- ::android::status_t init() override;
::android::status_t drain(StreamDescriptor::DrainMode) override;
::android::status_t flush() override;
::android::status_t pause() override;
- ::android::status_t standby() override;
- ::android::status_t start() override;
::android::status_t transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
int32_t* latencyMs) override;
- void shutdown() override;
// Overridden methods of 'StreamCommonImpl', called on a Binder thread.
- const ConnectedDevices& getConnectedDevices() const override;
ndk::ScopedAStatus setConnectedDevices(const ConnectedDevices& devices) override;
- private:
- using AlsaDeviceProxyDeleter = std::function<void(alsa_device_proxy*)>;
- using AlsaDeviceProxy = std::unique_ptr<alsa_device_proxy, AlsaDeviceProxyDeleter>;
-
- static std::optional<struct pcm_config> maybePopulateConfig(const StreamContext& context,
- bool isInput);
+ protected:
+ std::vector<alsa::DeviceProfile> getDeviceProfiles() override;
mutable std::mutex mLock;
-
- const size_t mFrameSizeBytes;
- const bool mIsInput;
- const std::optional<struct pcm_config> mConfig;
+ std::vector<alsa::DeviceProfile> mConnectedDeviceProfiles GUARDED_BY(mLock);
std::atomic<bool> mConnectedDevicesUpdated = false;
- // All fields below are only used on the worker thread.
- std::vector<AlsaDeviceProxy> mAlsaDeviceProxies;
};
class StreamInUsb final : public StreamUsb, public StreamIn {
@@ -94,7 +73,7 @@
ndk::ScopedAStatus getHwVolume(std::vector<float>* _aidl_return) override;
ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
- int mChannelCount;
+ const int mChannelCount;
std::vector<float> mHwVolumes;
};
diff --git a/audio/aidl/default/include/effect-impl/EffectContext.h b/audio/aidl/default/include/effect-impl/EffectContext.h
index 22cdb6b..698e7a5 100644
--- a/audio/aidl/default/include/effect-impl/EffectContext.h
+++ b/audio/aidl/default/include/effect-impl/EffectContext.h
@@ -124,11 +124,11 @@
virtual RetCode setCommon(const Parameter::Common& common) {
mCommon = common;
- LOG(INFO) << __func__ << mCommon.toString();
+ LOG(VERBOSE) << __func__ << mCommon.toString();
return RetCode::SUCCESS;
}
virtual Parameter::Common getCommon() {
- LOG(DEBUG) << __func__ << mCommon.toString();
+ LOG(VERBOSE) << __func__ << mCommon.toString();
return mCommon;
}
diff --git a/audio/aidl/default/include/effect-impl/EffectWorker.h b/audio/aidl/default/include/effect-impl/EffectWorker.h
index b456817..421429a 100644
--- a/audio/aidl/default/include/effect-impl/EffectWorker.h
+++ b/audio/aidl/default/include/effect-impl/EffectWorker.h
@@ -45,8 +45,8 @@
auto readSamples = inputMQ->availableToRead(), writeSamples = outputMQ->availableToWrite();
if (readSamples && writeSamples) {
auto processSamples = std::min(readSamples, writeSamples);
- LOG(DEBUG) << __func__ << " available to read " << readSamples << " available to write "
- << writeSamples << " process " << processSamples;
+ LOG(VERBOSE) << __func__ << " available to read " << readSamples
+ << " available to write " << writeSamples << " process " << processSamples;
auto buffer = mContext->getWorkBuffer();
inputMQ->read(buffer, processSamples);
@@ -54,8 +54,8 @@
IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples);
outputMQ->write(buffer, status.fmqProduced);
statusMQ->writeBlocking(&status, 1);
- LOG(DEBUG) << __func__ << " done processing, effect consumed " << status.fmqConsumed
- << " produced " << status.fmqProduced;
+ LOG(VERBOSE) << __func__ << " done processing, effect consumed " << status.fmqConsumed
+ << " produced " << status.fmqProduced;
} else {
// TODO: maybe add some sleep here to avoid busy waiting
}
diff --git a/audio/aidl/default/include/effectFactory-impl/EffectConfig.h b/audio/aidl/default/include/effectFactory-impl/EffectConfig.h
index f8a86e1..344846a 100644
--- a/audio/aidl/default/include/effectFactory-impl/EffectConfig.h
+++ b/audio/aidl/default/include/effectFactory-impl/EffectConfig.h
@@ -40,14 +40,15 @@
public:
explicit EffectConfig(const std::string& file);
- struct LibraryUuid {
+ struct Library {
std::string name; // library name
- ::aidl::android::media::audio::common::AudioUuid uuid;
+ ::aidl::android::media::audio::common::AudioUuid uuid; // implementation UUID
+ std::optional<::aidl::android::media::audio::common::AudioUuid> type; // optional type UUID
};
// <effects>
struct EffectLibraries {
- std::optional<struct LibraryUuid> proxyLibrary;
- std::vector<struct LibraryUuid> libraries;
+ std::optional<struct Library> proxyLibrary;
+ std::vector<struct Library> libraries;
};
int getSkippedElements() const { return mSkippedElements; }
@@ -56,7 +57,7 @@
return mEffectsMap;
}
- static bool findUuid(const std::string& xmlEffectName,
+ static bool findUuid(const std::pair<std::string, struct EffectLibraries>& effectElem,
::aidl::android::media::audio::common::AudioUuid* uuid);
using ProcessingLibrariesMap = std::map<Processing::Type, std::vector<struct EffectLibraries>>;
@@ -96,8 +97,8 @@
bool parseProcessing(Processing::Type::Tag typeTag, const tinyxml2::XMLElement& xml);
// Function to parse effect.library name and effect.uuid from xml
- bool parseLibraryUuid(const tinyxml2::XMLElement& xml, struct LibraryUuid& libraryUuid,
- bool isProxy = false);
+ bool parseLibrary(const tinyxml2::XMLElement& xml, struct Library& library,
+ bool isProxy = false);
const char* dump(const tinyxml2::XMLElement& element,
tinyxml2::XMLPrinter&& printer = {}) const;
diff --git a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
index ad59ca7..d0b8204 100644
--- a/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
+++ b/audio/aidl/default/include/effectFactory-impl/EffectFactory.h
@@ -24,6 +24,7 @@
#include <vector>
#include <aidl/android/hardware/audio/effect/BnFactory.h>
+#include <android-base/thread_annotations.h>
#include "EffectConfig.h"
namespace aidl::android::hardware::audio::effect {
@@ -82,9 +83,11 @@
private:
const EffectConfig mConfig;
~Factory();
+
+ std::mutex mMutex;
// Set of effect descriptors supported by the devices.
- std::set<Descriptor> mDescSet;
- std::set<Descriptor::Identity> mIdentitySet;
+ std::set<Descriptor> mDescSet GUARDED_BY(mMutex);
+ std::set<Descriptor::Identity> mIdentitySet GUARDED_BY(mMutex);
static constexpr int kMapEntryHandleIndex = 0;
static constexpr int kMapEntryInterfaceIndex = 1;
@@ -94,26 +97,29 @@
std::string /* library name */>
DlEntry;
- std::map<aidl::android::media::audio::common::AudioUuid /* implUUID */, DlEntry> mEffectLibMap;
+ std::map<aidl::android::media::audio::common::AudioUuid /* implUUID */, DlEntry> mEffectLibMap
+ GUARDED_BY(mMutex);
typedef std::pair<aidl::android::media::audio::common::AudioUuid, ndk::SpAIBinder> EffectEntry;
- std::map<std::weak_ptr<IEffect>, EffectEntry, std::owner_less<>> mEffectMap;
+ std::map<std::weak_ptr<IEffect>, EffectEntry, std::owner_less<>> mEffectMap GUARDED_BY(mMutex);
- ndk::ScopedAStatus destroyEffectImpl(const std::shared_ptr<IEffect>& in_handle);
- void cleanupEffectMap();
+ ndk::ScopedAStatus destroyEffectImpl_l(const std::shared_ptr<IEffect>& in_handle)
+ REQUIRES(mMutex);
+ void cleanupEffectMap_l() REQUIRES(mMutex);
bool openEffectLibrary(const ::aidl::android::media::audio::common::AudioUuid& impl,
const std::string& path);
void createIdentityWithConfig(
- const EffectConfig::LibraryUuid& configLib,
+ const EffectConfig::Library& configLib,
const ::aidl::android::media::audio::common::AudioUuid& typeUuidStr,
const std::optional<::aidl::android::media::audio::common::AudioUuid> proxyUuid);
- ndk::ScopedAStatus getDescriptorWithUuid(
- const aidl::android::media::audio::common::AudioUuid& uuid, Descriptor* desc);
+ ndk::ScopedAStatus getDescriptorWithUuid_l(
+ const aidl::android::media::audio::common::AudioUuid& uuid, Descriptor* desc)
+ REQUIRES(mMutex);
void loadEffectLibs();
/* Get effect_dl_interface_s from library handle */
- void getDlSyms(DlEntry& entry);
+ void getDlSyms_l(DlEntry& entry) REQUIRES(mMutex);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/main.cpp b/audio/aidl/default/main.cpp
index 12c0c4b..93fb366 100644
--- a/audio/aidl/default/main.cpp
+++ b/audio/aidl/default/main.cpp
@@ -16,20 +16,21 @@
#include <cstdlib>
#include <ctime>
+#include <sstream>
#include <utility>
+#include <vector>
#include <android-base/logging.h>
+#include <android-base/properties.h>
#include <android/binder_ibinder_platform.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include "core-impl/Config.h"
#include "core-impl/Module.h"
-#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.
@@ -52,18 +53,19 @@
CHECK_EQ(STATUS_OK, status);
// Make modules
- auto createModule = [](Module::Type type, const std::string& instance) {
+ auto createModule = [](Module::Type type) {
auto module = Module::createInstance(type);
ndk::SpAIBinder moduleBinder = module->asBinder();
- const std::string moduleName = std::string(Module::descriptor).append("/").append(instance);
+ std::stringstream moduleName;
+ moduleName << Module::descriptor << "/" << type;
AIBinder_setMinSchedulerPolicy(moduleBinder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
- binder_status_t status = AServiceManager_addService(moduleBinder.get(), moduleName.c_str());
+ binder_status_t status =
+ AServiceManager_addService(moduleBinder.get(), moduleName.str().c_str());
CHECK_EQ(STATUS_OK, status);
return std::make_pair(module, moduleBinder);
};
- auto modules = {createModule(Module::Type::DEFAULT, "default"),
- createModule(Module::Type::R_SUBMIX, "r_submix"),
- createModule(Module::Type::USB, "usb")};
+ auto modules = {createModule(Module::Type::DEFAULT), createModule(Module::Type::R_SUBMIX),
+ createModule(Module::Type::USB), createModule(Module::Type::STUB)};
(void)modules;
ABinderProcess_joinThreadPool();
diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
index 5af0d91..6d5185b 100644
--- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
@@ -179,6 +179,27 @@
: outWrite(buffer, frameCount, actualFrameCount));
}
+::android::status_t StreamRemoteSubmix::getPosition(StreamDescriptor::Position* position) {
+ sp<MonoPipeReader> source = mCurrentRoute->getSource();
+ if (source == nullptr) {
+ return ::android::NO_INIT;
+ }
+ const ssize_t framesInPipe = source->availableToRead();
+ if (framesInPipe < 0) {
+ return ::android::INVALID_OPERATION;
+ }
+ if (mIsInput) {
+ position->frames += framesInPipe;
+ } else {
+ if (position->frames > framesInPipe) {
+ position->frames -= framesInPipe;
+ } else {
+ position->frames = 0;
+ }
+ }
+ return ::android::OK;
+}
+
// Calculate the maximum size of the pipe buffer in frames for the specified stream.
size_t StreamRemoteSubmix::getStreamPipeSizeInFrames() {
auto pipeConfig = mCurrentRoute->mPipeConfig;
diff --git a/audio/aidl/default/stub/ModuleStub.cpp b/audio/aidl/default/stub/ModuleStub.cpp
new file mode 100644
index 0000000..a600752
--- /dev/null
+++ b/audio/aidl/default/stub/ModuleStub.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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 <vector>
+
+#define LOG_TAG "AHAL_ModuleStub"
+#include <Utils.h>
+#include <android-base/logging.h>
+
+#include "core-impl/Bluetooth.h"
+#include "core-impl/ModuleStub.h"
+#include "core-impl/StreamStub.h"
+
+using aidl::android::hardware::audio::common::SinkMetadata;
+using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::media::audio::common::AudioOffloadInfo;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::MicrophoneInfo;
+
+namespace aidl::android::hardware::audio::core {
+
+ndk::ScopedAStatus ModuleStub::getBluetooth(std::shared_ptr<IBluetooth>* _aidl_return) {
+ if (!mBluetooth) {
+ mBluetooth = ndk::SharedRefBase::make<Bluetooth>();
+ }
+ *_aidl_return = mBluetooth.getPtr();
+ LOG(DEBUG) << __func__ << ": returning instance of IBluetooth: " << _aidl_return->get();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleStub::getBluetoothA2dp(std::shared_ptr<IBluetoothA2dp>* _aidl_return) {
+ if (!mBluetoothA2dp) {
+ mBluetoothA2dp = ndk::SharedRefBase::make<BluetoothA2dp>();
+ }
+ *_aidl_return = mBluetoothA2dp.getPtr();
+ LOG(DEBUG) << __func__ << ": returning instance of IBluetoothA2dp: " << _aidl_return->get();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleStub::getBluetoothLe(std::shared_ptr<IBluetoothLe>* _aidl_return) {
+ if (!mBluetoothLe) {
+ mBluetoothLe = ndk::SharedRefBase::make<BluetoothLe>();
+ }
+ *_aidl_return = mBluetoothLe.getPtr();
+ LOG(DEBUG) << __func__ << ": returning instance of IBluetoothLe: " << _aidl_return->get();
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus ModuleStub::createInputStream(const SinkMetadata& sinkMetadata,
+ StreamContext&& context,
+ const std::vector<MicrophoneInfo>& microphones,
+ std::shared_ptr<StreamIn>* result) {
+ return createStreamInstance<StreamInStub>(result, sinkMetadata, std::move(context),
+ microphones);
+}
+
+ndk::ScopedAStatus ModuleStub::createOutputStream(
+ const SourceMetadata& sourceMetadata, StreamContext&& context,
+ const std::optional<AudioOffloadInfo>& offloadInfo, std::shared_ptr<StreamOut>* result) {
+ return createStreamInstance<StreamOutStub>(result, sourceMetadata, std::move(context),
+ offloadInfo);
+}
+
+} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/StreamStub.cpp b/audio/aidl/default/stub/StreamStub.cpp
similarity index 100%
rename from audio/aidl/default/StreamStub.cpp
rename to audio/aidl/default/stub/StreamStub.cpp
diff --git a/audio/aidl/default/usb/ModuleUsb.cpp b/audio/aidl/default/usb/ModuleUsb.cpp
index 5c9d477..a812e4d 100644
--- a/audio/aidl/default/usb/ModuleUsb.cpp
+++ b/audio/aidl/default/usb/ModuleUsb.cpp
@@ -14,68 +14,34 @@
* limitations under the License.
*/
-#define LOG_TAG "AHAL_ModuleUsb"
-
#include <vector>
+#define LOG_TAG "AHAL_ModuleUsb"
#include <Utils.h>
#include <android-base/logging.h>
-#include <tinyalsa/asoundlib.h>
#include "UsbAlsaMixerControl.h"
-#include "UsbAlsaUtils.h"
+#include "alsa/Utils.h"
#include "core-impl/ModuleUsb.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::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::AudioIoFlags;
using aidl::android::media::audio::common::AudioOffloadInfo;
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 aidl::android::media::audio::common::MicrophoneInfo;
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;
+bool isUsbDevicePort(const AudioPort& audioPort) {
+ return audioPort.ext.getTag() == AudioPortExt::Tag::device &&
+ audioPort.ext.get<AudioPortExt::Tag::device>().device.type.connection ==
+ AudioDeviceDescription::CONNECTION_USB;
}
} // namespace
@@ -122,55 +88,11 @@
}
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) {
+ if (!isUsbDevicePort(*audioPort)) {
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 = audioPort->flags.getTag() == AudioIoFlags::input;
- alsa_device_profile profile;
- profile_init(&profile, isInput ? PCM_IN : PCM_OUT);
- profile.card = alsaAddress[0];
- profile.device = alsaAddress[1];
- if (!profile_read_device_info(&profile)) {
- LOG(ERROR) << __func__ << ": failed to read device info, card=" << profile.card
- << ", device=" << profile.device;
- 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] != PCM_FORMAT_INVALID;
- ++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();
+ return ModuleAlsa::populateConnectedDevicePort(audioPort);
}
ndk::ScopedAStatus ModuleUsb::checkAudioPatchEndpointsMatch(
@@ -191,15 +113,14 @@
void ModuleUsb::onExternalDeviceConnectionChanged(
const ::aidl::android::media::audio::common::AudioPort& audioPort, bool connected) {
- if (audioPort.ext.getTag() != AudioPortExt::Tag::device) {
+ if (!isUsbDevicePort(audioPort)) {
return;
}
- const auto& address = audioPort.ext.get<AudioPortExt::Tag::device>().device.address;
- if (address.getTag() != AudioDeviceAddress::alsa) {
+ auto profile = alsa::getDeviceProfile(audioPort);
+ if (!profile.has_value()) {
return;
}
- const int card = address.get<AudioDeviceAddress::alsa>()[0];
- usb::UsbAlsaMixerControl::getInstance().setDeviceConnectionState(card, getMasterMute(),
+ usb::UsbAlsaMixerControl::getInstance().setDeviceConnectionState(profile->card, getMasterMute(),
getMasterVolume(), connected);
}
diff --git a/audio/aidl/default/usb/StreamUsb.cpp b/audio/aidl/default/usb/StreamUsb.cpp
index 17e1ab4..da0ad11 100644
--- a/audio/aidl/default/usb/StreamUsb.cpp
+++ b/audio/aidl/default/usb/StreamUsb.cpp
@@ -23,64 +23,20 @@
#include <error/expected_utils.h>
#include "UsbAlsaMixerControl.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::getChannelCount;
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;
-using aidl::android::media::audio::common::AudioPortExt;
using aidl::android::media::audio::common::MicrophoneDynamicInfo;
using aidl::android::media::audio::common::MicrophoneInfo;
-using android::OK;
-using android::status_t;
namespace aidl::android::hardware::audio::core {
StreamUsb::StreamUsb(const Metadata& metadata, StreamContext&& context)
- : StreamCommonImpl(metadata, std::move(context)),
- mFrameSizeBytes(getContext().getFrameSize()),
- mIsInput(isInput(metadata)),
- mConfig(maybePopulateConfig(getContext(), mIsInput)) {}
-
-// static
-std::optional<struct pcm_config> StreamUsb::maybePopulateConfig(const StreamContext& context,
- bool 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 std::nullopt;
- }
- config.format = usb::aidl2legacy_AudioFormatDescription_pcm_format(context.getFormat());
- if (config.format == PCM_FORMAT_INVALID) {
- LOG(ERROR) << __func__ << ": invalid format=" << context.getFormat().toString();
- return std::nullopt;
- }
- config.rate = context.getSampleRate();
- if (config.rate == 0) {
- LOG(ERROR) << __func__ << ": invalid sample rate=" << config.rate;
- return std::nullopt;
- }
- return config;
-}
-
-::android::status_t StreamUsb::init() {
- return mConfig.has_value() ? ::android::OK : ::android::NO_INIT;
-}
-
-const StreamCommonInterface::ConnectedDevices& StreamUsb::getConnectedDevices() const {
- std::lock_guard guard(mLock);
- return mConnectedDevices;
-}
+ : StreamAlsa(metadata, std::move(context)) {}
ndk::ScopedAStatus StreamUsb::setConnectedDevices(
const std::vector<AudioDevice>& connectedDevices) {
@@ -89,14 +45,19 @@
<< ") for input stream";
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
+ std::vector<alsa::DeviceProfile> connectedDeviceProfiles;
for (const auto& connectedDevice : connectedDevices) {
- if (connectedDevice.address.getTag() != AudioDeviceAddress::alsa) {
- LOG(ERROR) << __func__ << ": bad device address" << connectedDevice.address.toString();
+ auto profile = alsa::getDeviceProfile(connectedDevice, mIsInput);
+ if (!profile.has_value()) {
+ LOG(ERROR) << __func__
+ << ": unsupported device address=" << connectedDevice.address.toString();
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
+ connectedDeviceProfiles.push_back(*profile);
}
- std::lock_guard guard(mLock);
RETURN_STATUS_IF_ERROR(StreamCommonImpl::setConnectedDevices(connectedDevices));
+ std::lock_guard guard(mLock);
+ mConnectedDeviceProfiles = std::move(connectedDeviceProfiles);
mConnectedDevicesUpdated.store(true, std::memory_order_release);
return ndk::ScopedAStatus::ok();
}
@@ -119,87 +80,22 @@
::android::status_t StreamUsb::transfer(void* buffer, size_t frameCount, size_t* actualFrameCount,
int32_t* latencyMs) {
if (mConnectedDevicesUpdated.load(std::memory_order_acquire)) {
- // 'setConnectedDevices' has been called. I/O will be restarted.
+ // 'setConnectedDevices' was called. I/O will be restarted.
*actualFrameCount = 0;
*latencyMs = StreamDescriptor::LATENCY_UNKNOWN;
return ::android::OK;
}
- const size_t bytesToTransfer = frameCount * mFrameSizeBytes;
- unsigned maxLatency = 0;
- if (mIsInput) {
- if (mAlsaDeviceProxies.empty()) {
- LOG(FATAL) << __func__ << ": no input devices";
- return ::android::NO_INIT;
- }
- // For input case, only support single device.
- proxy_read(mAlsaDeviceProxies[0].get(), buffer, bytesToTransfer);
- maxLatency = proxy_get_latency(mAlsaDeviceProxies[0].get());
- } else {
- for (auto& proxy : mAlsaDeviceProxies) {
- proxy_write(proxy.get(), buffer, bytesToTransfer);
- maxLatency = std::max(maxLatency, proxy_get_latency(proxy.get()));
- }
- }
- *actualFrameCount = frameCount;
- maxLatency = std::min(maxLatency, static_cast<unsigned>(std::numeric_limits<int32_t>::max()));
- *latencyMs = maxLatency;
- return ::android::OK;
+ return StreamAlsa::transfer(buffer, frameCount, actualFrameCount, latencyMs);
}
-::android::status_t StreamUsb::standby() {
- mAlsaDeviceProxies.clear();
- return ::android::OK;
-}
-
-void StreamUsb::shutdown() {
- mAlsaDeviceProxies.clear();
-}
-
-::android::status_t StreamUsb::start() {
- std::vector<AudioDeviceAddress> connectedDevices;
+std::vector<alsa::DeviceProfile> StreamUsb::getDeviceProfiles() {
+ std::vector<alsa::DeviceProfile> connectedDevices;
{
std::lock_guard guard(mLock);
- std::transform(mConnectedDevices.begin(), mConnectedDevices.end(),
- std::back_inserter(connectedDevices),
- [](const auto& device) { return device.address; });
+ connectedDevices = mConnectedDeviceProfiles;
mConnectedDevicesUpdated.store(false, std::memory_order_release);
}
- decltype(mAlsaDeviceProxies) alsaDeviceProxies;
- for (const auto& device : connectedDevices) {
- alsa_device_profile profile;
- profile_init(&profile, mIsInput ? PCM_IN : PCM_OUT);
- 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;
- }
-
- AlsaDeviceProxy 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,
- const_cast<struct pcm_config*>(&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;
- }
- if (int err = proxy_open(proxy.get()); err != 0) {
- LOG(ERROR) << __func__ << ": failed to open device, address=" << device.toString()
- << " error=" << err;
- return ::android::UNKNOWN_ERROR;
- }
- alsaDeviceProxies.push_back(std::move(proxy));
- }
- mAlsaDeviceProxies = std::move(alsaDeviceProxies);
- return ::android::OK;
+ return connectedDevices;
}
StreamInUsb::StreamInUsb(const SinkMetadata& sinkMetadata, StreamContext&& context,
@@ -214,9 +110,9 @@
StreamOutUsb::StreamOutUsb(const SourceMetadata& sourceMetadata, StreamContext&& context,
const std::optional<AudioOffloadInfo>& offloadInfo)
- : StreamUsb(sourceMetadata, std::move(context)), StreamOut(offloadInfo) {
- mChannelCount = getChannelCount(getContext().getChannelLayout());
-}
+ : StreamUsb(sourceMetadata, std::move(context)),
+ StreamOut(offloadInfo),
+ mChannelCount(getChannelCount(getContext().getChannelLayout())) {}
ndk::ScopedAStatus StreamOutUsb::getHwVolume(std::vector<float>* _aidl_return) {
*_aidl_return = mHwVolumes;
@@ -224,17 +120,17 @@
}
ndk::ScopedAStatus StreamOutUsb::setHwVolume(const std::vector<float>& in_channelVolumes) {
+ // Avoid using mConnectedDeviceProfiles because it requires a lock.
for (const auto& device : getConnectedDevices()) {
- if (device.address.getTag() != AudioDeviceAddress::alsa) {
- LOG(DEBUG) << __func__ << ": skip as the device address is not alsa";
- continue;
- }
- const int card = device.address.get<AudioDeviceAddress::alsa>()[0];
- if (auto result =
- usb::UsbAlsaMixerControl::getInstance().setVolumes(card, in_channelVolumes);
- !result.isOk()) {
- LOG(ERROR) << __func__ << ": failed to set volume for device, card=" << card;
- return result;
+ if (auto deviceProfile = alsa::getDeviceProfile(device, mIsInput);
+ deviceProfile.has_value()) {
+ if (auto result = usb::UsbAlsaMixerControl::getInstance().setVolumes(
+ deviceProfile->card, in_channelVolumes);
+ !result.isOk()) {
+ LOG(ERROR) << __func__
+ << ": failed to set volume for device address=" << *deviceProfile;
+ return result;
+ }
}
}
mHwVolumes = in_channelVolumes;
diff --git a/audio/aidl/default/usb/UsbAlsaMixerControl.cpp b/audio/aidl/default/usb/UsbAlsaMixerControl.cpp
index 6c0c24b..769d739 100644
--- a/audio/aidl/default/usb/UsbAlsaMixerControl.cpp
+++ b/audio/aidl/default/usb/UsbAlsaMixerControl.cpp
@@ -17,144 +17,12 @@
#define LOG_TAG "AHAL_UsbAlsaMixerControl"
#include <android-base/logging.h>
-#include <cmath>
-#include <string>
-#include <vector>
-
#include <android/binder_status.h>
#include "UsbAlsaMixerControl.h"
namespace aidl::android::hardware::audio::core::usb {
-//-----------------------------------------------------------------------------
-
-MixerControl::MixerControl(struct mixer_ctl* ctl)
- : mCtl(ctl),
- mNumValues(mixer_ctl_get_num_values(ctl)),
- mMinValue(mixer_ctl_get_range_min(ctl)),
- mMaxValue(mixer_ctl_get_range_max(ctl)) {}
-
-unsigned int MixerControl::getNumValues() const {
- return mNumValues;
-}
-
-int MixerControl::getMaxValue() const {
- return mMaxValue;
-}
-
-int MixerControl::getMinValue() const {
- return mMinValue;
-}
-
-int MixerControl::setArray(const void* array, size_t count) {
- const std::lock_guard guard(mLock);
- return mixer_ctl_set_array(mCtl, array, count);
-}
-
-//-----------------------------------------------------------------------------
-
-// static
-const std::map<AlsaMixer::Control, std::vector<AlsaMixer::ControlNamesAndExpectedCtlType>>
- AlsaMixer::kPossibleControls = {
- {AlsaMixer::MASTER_SWITCH, {{"Master Playback Switch", MIXER_CTL_TYPE_BOOL}}},
- {AlsaMixer::MASTER_VOLUME, {{"Master Playback Volume", MIXER_CTL_TYPE_INT}}},
- {AlsaMixer::HW_VOLUME,
- {{"Headphone Playback Volume", MIXER_CTL_TYPE_INT},
- {"Headset Playback Volume", MIXER_CTL_TYPE_INT},
- {"PCM Playback Volume", MIXER_CTL_TYPE_INT}}}};
-
-// static
-std::map<AlsaMixer::Control, std::shared_ptr<MixerControl>> AlsaMixer::initializeMixerControls(
- struct mixer* mixer) {
- std::map<AlsaMixer::Control, std::shared_ptr<MixerControl>> mixerControls;
- std::string mixerCtlNames;
- for (const auto& [control, possibleCtls] : kPossibleControls) {
- for (const auto& [ctlName, expectedCtlType] : possibleCtls) {
- struct mixer_ctl* ctl = mixer_get_ctl_by_name(mixer, ctlName.c_str());
- if (ctl != nullptr && mixer_ctl_get_type(ctl) == expectedCtlType) {
- mixerControls.emplace(control, std::make_unique<MixerControl>(ctl));
- if (!mixerCtlNames.empty()) {
- mixerCtlNames += ",";
- }
- mixerCtlNames += ctlName;
- break;
- }
- }
- }
- LOG(DEBUG) << __func__ << ": available mixer control names=[" << mixerCtlNames << "]";
- return mixerControls;
-}
-
-AlsaMixer::AlsaMixer(struct mixer* mixer)
- : mMixer(mixer), mMixerControls(initializeMixerControls(mMixer)) {}
-
-AlsaMixer::~AlsaMixer() {
- mixer_close(mMixer);
-}
-
-namespace {
-
-int volumeFloatToInteger(float fValue, int maxValue, int minValue) {
- return minValue + std::ceil((maxValue - minValue) * fValue);
-}
-
-} // namespace
-
-ndk::ScopedAStatus AlsaMixer::setMasterMute(bool muted) {
- auto it = mMixerControls.find(AlsaMixer::MASTER_SWITCH);
- if (it == mMixerControls.end()) {
- return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
- }
- const int numValues = it->second->getNumValues();
- std::vector<int> values(numValues, muted ? 0 : 1);
- if (int err = it->second->setArray(values.data(), numValues); err != 0) {
- LOG(ERROR) << __func__ << ": failed to set master mute, err=" << err;
- return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
- }
- return ndk::ScopedAStatus::ok();
-}
-
-ndk::ScopedAStatus AlsaMixer::setMasterVolume(float volume) {
- auto it = mMixerControls.find(AlsaMixer::MASTER_VOLUME);
- if (it == mMixerControls.end()) {
- return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
- }
- const int numValues = it->second->getNumValues();
- std::vector<int> values(numValues, volumeFloatToInteger(volume, it->second->getMaxValue(),
- it->second->getMinValue()));
- if (int err = it->second->setArray(values.data(), numValues); err != 0) {
- LOG(ERROR) << __func__ << ": failed to set master volume, err=" << err;
- return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
- }
- return ndk::ScopedAStatus::ok();
-}
-
-ndk::ScopedAStatus AlsaMixer::setVolumes(std::vector<float> volumes) {
- auto it = mMixerControls.find(AlsaMixer::HW_VOLUME);
- if (it == mMixerControls.end()) {
- return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
- }
- const int numValues = it->second->getNumValues();
- if (numValues < 0) {
- LOG(FATAL) << __func__ << ": negative number of values: " << numValues;
- }
- const int maxValue = it->second->getMaxValue();
- const int minValue = it->second->getMinValue();
- std::vector<int> values;
- size_t i = 0;
- for (; i < static_cast<size_t>(numValues) && i < values.size(); ++i) {
- values.emplace_back(volumeFloatToInteger(volumes[i], maxValue, minValue));
- }
- if (int err = it->second->setArray(values.data(), values.size()); err != 0) {
- LOG(ERROR) << __func__ << ": failed to set volume, err=" << err;
- return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
- }
- return ndk::ScopedAStatus::ok();
-}
-
-//-----------------------------------------------------------------------------
-
// static
UsbAlsaMixerControl& UsbAlsaMixerControl::getInstance() {
static UsbAlsaMixerControl gInstance;
@@ -170,7 +38,7 @@
PLOG(ERROR) << __func__ << ": failed to open mixer for card=" << card;
return;
}
- auto alsaMixer = std::make_shared<AlsaMixer>(mixer);
+ auto alsaMixer = std::make_shared<alsa::Mixer>(mixer);
alsaMixer->setMasterMute(masterMuted);
alsaMixer->setMasterVolume(masterVolume);
const std::lock_guard guard(mLock);
@@ -209,7 +77,7 @@
return ndk::ScopedAStatus::ok();
}
-ndk::ScopedAStatus UsbAlsaMixerControl::setVolumes(int card, std::vector<float> volumes) {
+ndk::ScopedAStatus UsbAlsaMixerControl::setVolumes(int card, const std::vector<float>& volumes) {
auto alsaMixer = getAlsaMixer(card);
if (alsaMixer == nullptr) {
LOG(ERROR) << __func__ << ": no mixer control found for card=" << card;
@@ -218,13 +86,13 @@
return alsaMixer->setVolumes(volumes);
}
-std::shared_ptr<AlsaMixer> UsbAlsaMixerControl::getAlsaMixer(int card) {
+std::shared_ptr<alsa::Mixer> UsbAlsaMixerControl::getAlsaMixer(int card) {
const std::lock_guard guard(mLock);
const auto it = mMixerControls.find(card);
return it == mMixerControls.end() ? nullptr : it->second;
}
-std::map<int, std::shared_ptr<AlsaMixer>> UsbAlsaMixerControl::getAlsaMixers() {
+std::map<int, std::shared_ptr<alsa::Mixer>> UsbAlsaMixerControl::getAlsaMixers() {
const std::lock_guard guard(mLock);
return mMixerControls;
}
diff --git a/audio/aidl/default/usb/UsbAlsaMixerControl.h b/audio/aidl/default/usb/UsbAlsaMixerControl.h
index cbcddd8..c3265f8 100644
--- a/audio/aidl/default/usb/UsbAlsaMixerControl.h
+++ b/audio/aidl/default/usb/UsbAlsaMixerControl.h
@@ -19,67 +19,15 @@
#include <map>
#include <memory>
#include <mutex>
-#include <optional>
-#include <string>
#include <vector>
#include <android-base/thread_annotations.h>
#include <android/binder_auto_utils.h>
-extern "C" {
-#include <tinyalsa/mixer.h>
-}
+#include "alsa/Mixer.h"
namespace aidl::android::hardware::audio::core::usb {
-class MixerControl {
- public:
- explicit MixerControl(struct mixer_ctl* ctl);
-
- unsigned int getNumValues() const;
- int getMaxValue() const;
- int getMinValue() const;
- int setArray(const void* array, size_t count);
-
- private:
- std::mutex mLock;
- // The mixer_ctl object is owned by ALSA and will be released when the mixer is closed.
- struct mixer_ctl* mCtl GUARDED_BY(mLock);
- const unsigned int mNumValues;
- const int mMinValue;
- const int mMaxValue;
-};
-
-class AlsaMixer {
- public:
- explicit AlsaMixer(struct mixer* mixer);
-
- ~AlsaMixer();
-
- bool isValid() const { return mMixer != nullptr; }
-
- ndk::ScopedAStatus setMasterMute(bool muted);
- ndk::ScopedAStatus setMasterVolume(float volume);
- ndk::ScopedAStatus setVolumes(std::vector<float> volumes);
-
- private:
- enum Control {
- MASTER_SWITCH,
- MASTER_VOLUME,
- HW_VOLUME,
- };
- using ControlNamesAndExpectedCtlType = std::pair<std::string, enum mixer_ctl_type>;
- static const std::map<Control, std::vector<ControlNamesAndExpectedCtlType>> kPossibleControls;
- static std::map<Control, std::shared_ptr<MixerControl>> initializeMixerControls(
- struct mixer* mixer);
-
- // The mixer object is owned by ALSA and will be released when the mixer is closed.
- struct mixer* mMixer;
- // `mMixerControls` will only be initialized in constructor. After that, it wil only be
- // read but not be modified.
- const std::map<Control, std::shared_ptr<MixerControl>> mMixerControls;
-};
-
class UsbAlsaMixerControl {
public:
static UsbAlsaMixerControl& getInstance();
@@ -91,16 +39,16 @@
ndk::ScopedAStatus setMasterMute(bool muted);
ndk::ScopedAStatus setMasterVolume(float volume);
// The volume settings can be different on sound cards. It is controlled by streams.
- ndk::ScopedAStatus setVolumes(int card, std::vector<float> volumes);
+ ndk::ScopedAStatus setVolumes(int card, const std::vector<float>& volumes);
private:
- std::shared_ptr<AlsaMixer> getAlsaMixer(int card);
- std::map<int, std::shared_ptr<AlsaMixer>> getAlsaMixers();
+ std::shared_ptr<alsa::Mixer> getAlsaMixer(int card);
+ std::map<int, std::shared_ptr<alsa::Mixer>> getAlsaMixers();
std::mutex mLock;
// A map whose key is the card number and value is a shared pointer to corresponding
// AlsaMixer object.
- std::map<int, std::shared_ptr<AlsaMixer>> mMixerControls GUARDED_BY(mLock);
+ std::map<int, std::shared_ptr<alsa::Mixer>> mMixerControls GUARDED_BY(mLock);
};
} // namespace aidl::android::hardware::audio::core::usb
diff --git a/audio/aidl/default/usb/UsbAlsaUtils.cpp b/audio/aidl/default/usb/UsbAlsaUtils.cpp
deleted file mode 100644
index 74d9c28..0000000
--- a/audio/aidl/default/usb/UsbAlsaUtils.cpp
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * 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::hardware::audio::common::getChannelCount;
-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;
-
-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::FIXED_Q_8_24), PCM_FORMAT_S24_LE},
- {make_AudioFormatDescription(PcmType::INT_24_BIT), 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
diff --git a/audio/aidl/default/usb/UsbAlsaUtils.h b/audio/aidl/default/usb/UsbAlsaUtils.h
deleted file mode 100644
index 2d2f0f4..0000000
--- a/audio/aidl/default/usb/UsbAlsaUtils.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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/vts/VtsHalAECTargetTest.cpp b/audio/aidl/vts/VtsHalAECTargetTest.cpp
index 1a7c3d4..0354e3c 100644
--- a/audio/aidl/vts/VtsHalAECTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAECTargetTest.cpp
@@ -51,7 +51,7 @@
ASSERT_NE(nullptr, mFactory);
ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
- Parameter::Specific specific = getDefaultParamSpecific();
+ auto specific = getDefaultParamSpecific();
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
@@ -65,8 +65,13 @@
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
- Parameter::Specific getDefaultParamSpecific() {
- AcousticEchoCanceler aec = AcousticEchoCanceler::make<AcousticEchoCanceler::echoDelayUs>(0);
+ std::optional<Parameter::Specific> getDefaultParamSpecific() {
+ auto aec = AcousticEchoCanceler::make<AcousticEchoCanceler::echoDelayUs>(0);
+ if (!isParameterValid<AcousticEchoCanceler, Range::acousticEchoCanceler>(aec,
+ mDescriptor)) {
+ return std::nullopt;
+ }
+
Parameter::Specific specific =
Parameter::Specific::make<Parameter::Specific::acousticEchoCanceler>(aec);
return specific;
diff --git a/audio/aidl/vts/VtsHalNSTargetTest.cpp b/audio/aidl/vts/VtsHalNSTargetTest.cpp
index bbb11fc..624d5d2 100644
--- a/audio/aidl/vts/VtsHalNSTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalNSTargetTest.cpp
@@ -48,7 +48,7 @@
ASSERT_NE(nullptr, mFactory);
ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
- Parameter::Specific specific = getDefaultParamSpecific();
+ std::optional<Parameter::Specific> specific = getDefaultParamSpecific();
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
@@ -62,9 +62,13 @@
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
- Parameter::Specific getDefaultParamSpecific() {
+ std::optional<Parameter::Specific> getDefaultParamSpecific() {
NoiseSuppression ns =
NoiseSuppression::make<NoiseSuppression::level>(NoiseSuppression::Level::MEDIUM);
+ if (!isParameterValid<NoiseSuppression, Range::noiseSuppression>(ns, mDescriptor)) {
+ return std::nullopt;
+ }
+
Parameter::Specific specific =
Parameter::Specific::make<Parameter::Specific::noiseSuppression>(ns);
return specific;
@@ -85,7 +89,9 @@
// validate parameter
Descriptor desc;
ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
- const binder_exception_t expected = EX_NONE;
+ const bool valid =
+ isParameterValid<NoiseSuppression, Range::noiseSuppression>(ns, desc);
+ const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
// set parameter
Parameter expectParam;
diff --git a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
index 5f5455a..9757287 100644
--- a/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
+++ b/biometrics/fingerprint/aidl/default/FakeFingerprintEngine.cpp
@@ -89,24 +89,29 @@
}
void FakeFingerprintEngine::fingerDownAction() {
+ bool isTerminal = false;
LOG(INFO) << __func__;
switch (mWorkMode) {
case WorkMode::kAuthenticate:
- onAuthenticateFingerDown(mCb, mOperationId, mCancel);
+ isTerminal = onAuthenticateFingerDown(mCb, mOperationId, mCancel);
break;
case WorkMode::kEnroll:
- onEnrollFingerDown(mCb, mHat, mCancel);
+ isTerminal = onEnrollFingerDown(mCb, mHat, mCancel);
break;
case WorkMode::kDetectInteract:
- onDetectInteractFingerDown(mCb, mCancel);
+ isTerminal = onDetectInteractFingerDown(mCb, mCancel);
break;
default:
LOG(WARNING) << "unexpected mode: on fingerDownAction(), " << (int)mWorkMode;
break;
}
+
+ if (isTerminal) {
+ mWorkMode = WorkMode::kIdle;
+ }
}
-void FakeFingerprintEngine::onEnrollFingerDown(ISessionCallback* cb,
+bool FakeFingerprintEngine::onEnrollFingerDown(ISessionCallback* cb,
const keymaster::HardwareAuthToken& hat,
const std::future<void>& cancel) {
BEGIN_OP(getLatency(FingerprintHalProperties::operation_enroll_latency()));
@@ -115,7 +120,7 @@
if (hat.mac.empty()) {
LOG(ERROR) << "Fail: hat";
cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
- return;
+ return true;
}
// Force error-out
@@ -124,7 +129,7 @@
LOG(ERROR) << "Fail: operation_enroll_error";
auto ec = convertError(err);
cb->onError(ec.first, ec.second);
- return;
+ return true;
}
// Format is "<id>:<progress_ms-[acquiredInfo..]>,...:<result>
@@ -133,7 +138,7 @@
if (parts.size() != 3) {
LOG(ERROR) << "Fail: invalid next_enrollment:" << nextEnroll;
cb->onError(Error::VENDOR, 0 /* vendorError */);
- return;
+ return true;
}
auto enrollmentId = std::stoi(parts[0]);
auto progress = parseEnrollmentCapture(parts[1]);
@@ -149,7 +154,7 @@
if (shouldCancel(cancel)) {
LOG(ERROR) << "Fail: cancel";
cb->onError(Error::CANCELED, 0 /* vendorCode */);
- return;
+ return true;
}
auto ac = convertAcquiredInfo(acquired[j]);
cb->onAcquired(ac.first, ac.second);
@@ -175,9 +180,11 @@
cb->onEnrollmentProgress(enrollmentId, left);
}
}
+
+ return true;
}
-void FakeFingerprintEngine::onAuthenticateFingerDown(ISessionCallback* cb,
+bool FakeFingerprintEngine::onAuthenticateFingerDown(ISessionCallback* cb,
int64_t /* operationId */,
const std::future<void>& cancel) {
BEGIN_OP(getLatency(FingerprintHalProperties::operation_authenticate_latency()));
@@ -191,11 +198,13 @@
if (N == 0) {
LOG(ERROR) << "Fail to parse authentiate acquired info: " + acquired;
cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
- return;
+ return true;
}
// got lockout?
- if (checkSensorLockout(cb)) return;
+ if (checkSensorLockout(cb)) {
+ return FakeLockoutTracker::LockoutMode::kPermanent == mLockoutTracker.getMode();
+ }
int i = 0;
do {
@@ -203,7 +212,7 @@
LOG(ERROR) << "Fail: operation_authenticate_fails";
mLockoutTracker.addFailedAttempt();
cb->onAuthenticationFailed();
- return;
+ return false;
}
auto err = FingerprintHalProperties::operation_authenticate_error().value_or(0);
@@ -211,20 +220,21 @@
LOG(ERROR) << "Fail: operation_authenticate_error";
auto ec = convertError(err);
cb->onError(ec.first, ec.second);
- return;
+ return true; /* simply terminating current operation for any user inserted error,
+ revisit if tests need*/
}
if (FingerprintHalProperties::lockout().value_or(false)) {
LOG(ERROR) << "Fail: lockout";
cb->onLockoutPermanent();
cb->onError(Error::HW_UNAVAILABLE, 0 /* vendorError */);
- return;
+ return true;
}
if (shouldCancel(cancel)) {
LOG(ERROR) << "Fail: cancel";
cb->onError(Error::CANCELED, 0 /* vendorCode */);
- return;
+ return true;
}
if (i < N) {
@@ -242,16 +252,17 @@
if (id > 0 && isEnrolled) {
cb->onAuthenticationSucceeded(id, {} /* hat */);
mLockoutTracker.reset();
- return;
+ return true;
} else {
LOG(ERROR) << "Fail: fingerprint not enrolled";
cb->onAuthenticationFailed();
mLockoutTracker.addFailedAttempt();
checkSensorLockout(cb);
+ return true;
}
}
-void FakeFingerprintEngine::onDetectInteractFingerDown(ISessionCallback* cb,
+bool FakeFingerprintEngine::onDetectInteractFingerDown(ISessionCallback* cb,
const std::future<void>& cancel) {
BEGIN_OP(getLatency(FingerprintHalProperties::operation_detect_interaction_latency()));
@@ -266,7 +277,7 @@
if (N == 0) {
LOG(ERROR) << "Fail to parse detect interaction acquired info: " + acquired;
cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
- return;
+ return true;
}
int i = 0;
@@ -276,13 +287,13 @@
LOG(ERROR) << "Fail: operation_detect_interaction_error";
auto ec = convertError(err);
cb->onError(ec.first, ec.second);
- return;
+ return true;
}
if (shouldCancel(cancel)) {
LOG(ERROR) << "Fail: cancel";
cb->onError(Error::CANCELED, 0 /* vendorCode */);
- return;
+ return true;
}
if (i < N) {
@@ -299,10 +310,12 @@
if (id <= 0 || !isEnrolled) {
LOG(ERROR) << "Fail: not enrolled";
cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
- return;
+ return true;
}
cb->onInteractionDetected();
+
+ return true;
}
void FakeFingerprintEngine::enumerateEnrollmentsImpl(ISessionCallback* cb) {
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
index 8ac7a95..a06b786 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
@@ -94,10 +94,10 @@
virtual void updateContext(WorkMode mode, ISessionCallback* cb, std::future<void>& cancel,
int64_t operationId, const keymaster::HardwareAuthToken& hat);
- void onEnrollFingerDown(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
+ bool onEnrollFingerDown(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat,
const std::future<void>& cancel);
- void onAuthenticateFingerDown(ISessionCallback* cb, int64_t, const std::future<void>& cancel);
- void onDetectInteractFingerDown(ISessionCallback* cb, const std::future<void>& cancel);
+ bool onAuthenticateFingerDown(ISessionCallback* cb, int64_t, const std::future<void>& cancel);
+ bool onDetectInteractFingerDown(ISessionCallback* cb, const std::future<void>& cancel);
WorkMode mWorkMode;
ISessionCallback* mCb;
diff --git a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
index 86207a5..e7e8a47 100644
--- a/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
+++ b/biometrics/fingerprint/aidl/default/tests/FakeFingerprintEngineTest.cpp
@@ -132,6 +132,8 @@
FingerprintHalProperties::operation_enroll_latency({});
FingerprintHalProperties::operation_authenticate_latency({});
FingerprintHalProperties::operation_detect_interaction_latency({});
+ FingerprintHalProperties::operation_authenticate_fails(false);
+ FingerprintHalProperties::operation_detect_interaction_latency({});
}
FakeFingerprintEngine mEngine;
@@ -185,6 +187,7 @@
ASSERT_EQ(4, FingerprintHalProperties::enrollments()[0].value());
ASSERT_EQ(4, mCallback->mLastEnrolled);
ASSERT_EQ(1, mCallback->mLastAcquiredInfo);
+ ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kIdle);
}
TEST_F(FakeFingerprintEngineTest, EnrollCancel) {
@@ -239,6 +242,7 @@
ASSERT_FALSE(mCallback->mAuthenticateFailed);
ASSERT_EQ(2, mCallback->mLastAuthenticated);
ASSERT_EQ(1, mCallback->mLastAcquiredInfo);
+ ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kIdle);
}
TEST_F(FakeFingerprintEngineTest, AuthenticateCancel) {
@@ -293,6 +297,14 @@
ASSERT_EQ(mCallback->mErrorVendorCode, 9);
}
+TEST_F(FakeFingerprintEngineTest, AuthenticateFails) {
+ FingerprintHalProperties::operation_authenticate_fails(true);
+ mEngine.authenticateImpl(mCallback.get(), 0, mCancel.get_future());
+ mEngine.fingerDownAction();
+ ASSERT_TRUE(mCallback->mAuthenticateFailed);
+ ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kAuthenticate);
+}
+
TEST_F(FakeFingerprintEngineTest, AuthenticateAcquired) {
FingerprintHalProperties::lockout(false);
FingerprintHalProperties::enrollments({1, 2});
@@ -318,6 +330,7 @@
mEngine.fingerDownAction();
ASSERT_EQ(1, mCallback->mInteractionDetectedCount);
ASSERT_EQ(1, mCallback->mLastAcquiredInfo);
+ ASSERT_EQ(mEngine.getWorkMode(), FakeFingerprintEngine::WorkMode::kIdle);
}
TEST_F(FakeFingerprintEngineTest, InteractionDetectCancel) {
@@ -483,7 +496,6 @@
FingerprintHalProperties::operation_detect_interaction_latency()));
}
ASSERT_TRUE(latencySet.size() > 95);
- FingerprintHalProperties::operation_detect_interaction_latency({});
}
} // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp b/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp
index e5222a7..24eb4d0 100644
--- a/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp
+++ b/bluetooth/aidl/vts/VtsHalBluetoothTargetTest.cpp
@@ -222,6 +222,8 @@
int wait_for_completed_packets_event(uint16_t handle);
void send_and_wait_for_cmd_complete(std::unique_ptr<CommandBuilder> cmd,
std::vector<uint8_t>& cmd_complete);
+ void reassemble_sco_loopback_pkt(std::vector<uint8_t>& scoPackets,
+ size_t size);
// A simple test implementation of BluetoothHciCallbacks.
class BluetoothHciCallbacks
@@ -569,6 +571,11 @@
ASSERT_TRUE(
sco_queue.tryPopWithTimeout(sco_loopback, kWaitForScoDataTimeout));
+ if (sco_loopback.size() < size) {
+ // The packets may have been split for USB. Reassemble before checking.
+ reassemble_sco_loopback_pkt(sco_loopback, size);
+ }
+
ASSERT_EQ(sco_packet, sco_loopback);
}
logger.setTotalBytes(num_packets * size * 2);
@@ -703,6 +710,22 @@
wait_for_command_complete_event(view.GetOpCode(), cmd_complete));
}
+// Handle the loopback packet.
+void BluetoothAidlTest::reassemble_sco_loopback_pkt(std::vector<uint8_t>& scoPackets,
+ size_t size) {
+ std::vector<uint8_t> sco_packet_whole;
+ sco_packet_whole.assign(scoPackets.begin(), scoPackets.end());
+ while (size + 3 > sco_packet_whole.size()) {
+ std::vector<uint8_t> sco_packets;
+ ASSERT_TRUE(
+ sco_queue.tryPopWithTimeout(sco_packets, kWaitForScoDataTimeout));
+ sco_packet_whole.insert(sco_packet_whole.end(), sco_packets.begin() + 3,
+ sco_packets.end());
+ }
+ scoPackets.assign(sco_packet_whole.begin(), sco_packet_whole.end());
+ scoPackets[2] = size;
+}
+
// Empty test: Initialize()/Close() are called in SetUp()/TearDown().
TEST_P(BluetoothAidlTest, InitializeAndClose) {}
diff --git a/bluetooth/audio/aidl/vts/Android.bp b/bluetooth/audio/aidl/vts/Android.bp
index 0a2a89a..3e6953f 100644
--- a/bluetooth/audio/aidl/vts/Android.bp
+++ b/bluetooth/audio/aidl/vts/Android.bp
@@ -15,11 +15,14 @@
],
tidy_timeout_srcs: ["VtsHalBluetoothAudioTargetTest.cpp"],
srcs: ["VtsHalBluetoothAudioTargetTest.cpp"],
- shared_libs: [
+ static_libs: [
"android.hardware.audio.common-V1-ndk",
"android.hardware.bluetooth.audio-V3-ndk",
"android.hardware.common-V2-ndk",
"android.hardware.common.fmq-V1-ndk",
+ "android.media.audio.common.types-V2-ndk",
+ ],
+ shared_libs: [
"libbase",
"libbinder_ndk",
"libcutils",
diff --git a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
index 356673f..8bee1b2 100644
--- a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
+++ b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
@@ -32,11 +32,11 @@
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
#include <broadcastradio-utils-aidl/Utils.h>
-#include <broadcastradio-vts-utils/mock-timeout.h>
#include <cutils/bitops.h>
#include <gmock/gmock.h>
#include <chrono>
+#include <condition_variable>
#include <optional>
#include <regex>
@@ -61,11 +61,6 @@
namespace bcutils = ::aidl::android::hardware::broadcastradio::utils;
-inline constexpr std::chrono::seconds kTuneTimeoutSec =
- std::chrono::seconds(IBroadcastRadio::TUNER_TIMEOUT_MS * 1000);
-inline constexpr std::chrono::seconds kProgramListScanTimeoutSec =
- std::chrono::seconds(IBroadcastRadio::LIST_COMPLETE_TIMEOUT_MS * 1000);
-
const ConfigFlag kConfigFlagValues[] = {
ConfigFlag::FORCE_MONO,
ConfigFlag::FORCE_ANALOG,
@@ -108,20 +103,68 @@
} // namespace
-class TunerCallbackMock : public BnTunerCallback {
+class CallbackFlag final {
public:
- TunerCallbackMock();
+ CallbackFlag(int timeoutMs) { mTimeoutMs = timeoutMs; }
+ /**
+ * Notify that the callback is called.
+ */
+ void notify() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mCalled = true;
+ lock.unlock();
+ mCv.notify_all();
+ };
+
+ /**
+ * Wait for the timeout passed into the constructor.
+ */
+ bool wait() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ return mCv.wait_for(lock, std::chrono::milliseconds(mTimeoutMs),
+ [this] { return mCalled; });
+ };
+
+ /**
+ * Reset the callback to not called.
+ */
+ void reset() {
+ std::unique_lock<std::mutex> lock(mMutex);
+ mCalled = false;
+ }
+
+ private:
+ std::mutex mMutex;
+ bool mCalled GUARDED_BY(mMutex) = false;
+ std::condition_variable mCv;
+ int mTimeoutMs;
+};
+
+class TunerCallbackImpl final : public BnTunerCallback {
+ public:
+ TunerCallbackImpl();
ScopedAStatus onTuneFailed(Result result, const ProgramSelector& selector) override;
- MOCK_TIMEOUT_METHOD1(onCurrentProgramInfoChangedMock, ScopedAStatus(const ProgramInfo&));
ScopedAStatus onCurrentProgramInfoChanged(const ProgramInfo& info) override;
ScopedAStatus onProgramListUpdated(const ProgramListChunk& chunk) override;
- MOCK_METHOD1(onAntennaStateChange, ScopedAStatus(bool connected));
- MOCK_METHOD1(onParametersUpdated, ScopedAStatus(const vector<VendorKeyValue>& parameters));
- MOCK_METHOD2(onConfigFlagUpdated, ScopedAStatus(ConfigFlag in_flag, bool in_value));
- MOCK_TIMEOUT_METHOD0(onProgramListReady, void());
+ ScopedAStatus onParametersUpdated(const vector<VendorKeyValue>& parameters) override;
+ ScopedAStatus onAntennaStateChange(bool connected) override;
+ ScopedAStatus onConfigFlagUpdated(ConfigFlag in_flag, bool in_value) override;
+ bool waitOnCurrentProgramInfoChangedCallback();
+ bool waitProgramReady();
+ void reset();
+
+ bool getAntennaConnectionState();
+ ProgramInfo getCurrentProgramInfo();
+ bcutils::ProgramInfoSet getProgramList();
+
+ private:
std::mutex mLock;
+ bool mAntennaConnectionState GUARDED_BY(mLock);
+ ProgramInfo mCurrentProgramInfo GUARDED_BY(mLock);
bcutils::ProgramInfoSet mProgramList GUARDED_BY(mLock);
+ CallbackFlag mOnCurrentProgramInfoChangedFlag = CallbackFlag(IBroadcastRadio::TUNER_TIMEOUT_MS);
+ CallbackFlag mOnProgramListReadyFlag = CallbackFlag(IBroadcastRadio::LIST_COMPLETE_TIMEOUT_MS);
};
struct AnnouncementListenerMock : public BnAnnouncementListener {
@@ -139,7 +182,7 @@
std::shared_ptr<IBroadcastRadio> mModule;
Properties mProperties;
- std::shared_ptr<TunerCallbackMock> mCallback = SharedRefBase::make<TunerCallbackMock>();
+ std::shared_ptr<TunerCallbackImpl> mCallback;
};
MATCHER_P(InfoHasId, id, string(negation ? "does not contain" : "contains") + " " + id.toString()) {
@@ -147,20 +190,18 @@
return ids.end() != find(ids.begin(), ids.end(), id.value);
}
-TunerCallbackMock::TunerCallbackMock() {
- EXPECT_TIMEOUT_CALL(*this, onCurrentProgramInfoChangedMock, _).Times(AnyNumber());
-
- // we expect the antenna is connected through the whole test
- EXPECT_CALL(*this, onAntennaStateChange(false)).Times(0);
+TunerCallbackImpl::TunerCallbackImpl() {
+ mAntennaConnectionState = true;
}
-ScopedAStatus TunerCallbackMock::onTuneFailed(Result result, const ProgramSelector& selector) {
+ScopedAStatus TunerCallbackImpl::onTuneFailed(Result result, const ProgramSelector& selector) {
LOG(DEBUG) << "Tune failed for selector" << selector.toString();
EXPECT_TRUE(result == Result::CANCELED);
return ndk::ScopedAStatus::ok();
}
-ScopedAStatus TunerCallbackMock::onCurrentProgramInfoChanged(const ProgramInfo& info) {
+ScopedAStatus TunerCallbackImpl::onCurrentProgramInfoChanged(const ProgramInfo& info) {
+ LOG(DEBUG) << "onCurrentProgramInfoChanged called";
for (const auto& id : info.selector) {
EXPECT_NE(id.type, IdentifierType::INVALID);
}
@@ -196,21 +237,75 @@
}
}
- return onCurrentProgramInfoChangedMock(info);
+ {
+ std::lock_guard<std::mutex> lk(mLock);
+ mCurrentProgramInfo = info;
+ }
+
+ mOnCurrentProgramInfoChangedFlag.notify();
+ return ndk::ScopedAStatus::ok();
}
-ScopedAStatus TunerCallbackMock::onProgramListUpdated(const ProgramListChunk& chunk) {
- std::lock_guard<std::mutex> lk(mLock);
-
- updateProgramList(chunk, &mProgramList);
+ScopedAStatus TunerCallbackImpl::onProgramListUpdated(const ProgramListChunk& chunk) {
+ LOG(DEBUG) << "onProgramListUpdated called";
+ {
+ std::lock_guard<std::mutex> lk(mLock);
+ updateProgramList(chunk, &mProgramList);
+ }
if (chunk.complete) {
- onProgramListReady();
+ mOnProgramListReadyFlag.notify();
}
return ndk::ScopedAStatus::ok();
}
+ScopedAStatus TunerCallbackImpl::onParametersUpdated(
+ [[maybe_unused]] const vector<VendorKeyValue>& parameters) {
+ return ndk::ScopedAStatus::ok();
+}
+
+ScopedAStatus TunerCallbackImpl::onAntennaStateChange(bool connected) {
+ if (!connected) {
+ std::lock_guard<std::mutex> lk(mLock);
+ mAntennaConnectionState = false;
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ScopedAStatus TunerCallbackImpl::onConfigFlagUpdated([[maybe_unused]] ConfigFlag in_flag,
+ [[maybe_unused]] bool in_value) {
+ return ndk::ScopedAStatus::ok();
+}
+
+bool TunerCallbackImpl::waitOnCurrentProgramInfoChangedCallback() {
+ return mOnCurrentProgramInfoChangedFlag.wait();
+}
+
+bool TunerCallbackImpl::waitProgramReady() {
+ return mOnProgramListReadyFlag.wait();
+}
+
+void TunerCallbackImpl::reset() {
+ mOnCurrentProgramInfoChangedFlag.reset();
+ mOnProgramListReadyFlag.reset();
+}
+
+bool TunerCallbackImpl::getAntennaConnectionState() {
+ std::lock_guard<std::mutex> lk(mLock);
+ return mAntennaConnectionState;
+}
+
+ProgramInfo TunerCallbackImpl::getCurrentProgramInfo() {
+ std::lock_guard<std::mutex> lk(mLock);
+ return mCurrentProgramInfo;
+}
+
+bcutils::ProgramInfoSet TunerCallbackImpl::getProgramList() {
+ std::lock_guard<std::mutex> lk(mLock);
+ return mProgramList;
+}
+
void BroadcastRadioHalTest::SetUp() {
EXPECT_EQ(mModule.get(), nullptr) << "Module is already open";
@@ -228,6 +323,8 @@
EXPECT_FALSE(mProperties.product.empty());
EXPECT_GT(mProperties.supportedIdentifierTypes.size(), 0u);
+ mCallback = SharedRefBase::make<TunerCallbackImpl>();
+
// set callback
EXPECT_TRUE(mModule->setTunerCallback(mCallback).isOk());
}
@@ -236,6 +333,11 @@
if (mModule) {
ASSERT_TRUE(mModule->unsetTunerCallback().isOk());
}
+ if (mCallback) {
+ // we expect the antenna is connected through the whole test
+ EXPECT_TRUE(mCallback->getAntennaConnectionState());
+ mCallback = nullptr;
+ }
}
bool BroadcastRadioHalTest::getAmFmRegionConfig(bool full, AmFmRegionConfig* config) {
@@ -256,7 +358,7 @@
std::optional<bcutils::ProgramInfoSet> BroadcastRadioHalTest::getProgramList(
const ProgramFilter& filter) {
- EXPECT_TIMEOUT_CALL(*mCallback, onProgramListReady).Times(AnyNumber());
+ mCallback->reset();
auto startResult = mModule->startProgramListUpdates(filter);
@@ -268,13 +370,13 @@
if (!startResult.isOk()) {
return std::nullopt;
}
- EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onProgramListReady, kProgramListScanTimeoutSec);
+ EXPECT_TRUE(mCallback->waitProgramReady());
auto stopResult = mModule->stopProgramListUpdates();
EXPECT_TRUE(stopResult.isOk());
- return mCallback->mProgramList;
+ return mCallback->getProgramList();
}
/**
@@ -456,7 +558,7 @@
* - if it is supported, the test is ignored;
*/
TEST_P(BroadcastRadioHalTest, TuneFailsWithNotSupported) {
- LOG(DEBUG) << "TuneFailsWithInvalid Test";
+ LOG(DEBUG) << "TuneFailsWithNotSupported Test";
vector<ProgramIdentifier> supportTestId = {
makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, 0), // invalid
@@ -477,9 +579,9 @@
for (const auto& id : supportTestId) {
ProgramSelector sel{id, {}};
- auto result = mModule->tune(sel);
-
if (!bcutils::isSupported(mProperties, sel)) {
+ auto result = mModule->tune(sel);
+
EXPECT_EQ(result.getServiceSpecificError(), notSupportedError);
}
}
@@ -508,9 +610,9 @@
for (const auto& id : invalidId) {
ProgramSelector sel{id, {}};
- auto result = mModule->tune(sel);
-
if (bcutils::isSupported(mProperties, sel)) {
+ auto result = mModule->tune(sel);
+
EXPECT_EQ(result.getServiceSpecificError(), invalidArgumentsError);
}
}
@@ -549,13 +651,7 @@
int64_t freq = 90900; // 90.9 FM
ProgramSelector sel = makeSelectorAmfm(freq);
// try tuning
- ProgramInfo infoCb = {};
- EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock,
- InfoHasId(makeIdentifier(IdentifierType::AMFM_FREQUENCY_KHZ, freq)))
- .Times(AnyNumber())
- .WillOnce(DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(ndk::ScopedAStatus::ok()))))
- .WillRepeatedly(testing::InvokeWithoutArgs([] { return ndk::ScopedAStatus::ok(); }));
-
+ mCallback->reset();
auto result = mModule->tune(sel);
// expect a failure if it's not supported
@@ -566,7 +662,8 @@
// expect a callback if it succeeds
EXPECT_TRUE(result.isOk());
- EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec);
+ EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
+ ProgramInfo infoCb = mCallback->getCurrentProgramInfo();
LOG(DEBUG) << "Current program info: " << infoCb.toString();
@@ -638,12 +735,6 @@
}
// try tuning
- ProgramInfo infoCb = {};
- EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock,
- InfoHasId(makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, freq)))
- .Times(AnyNumber())
- .WillOnce(
- DoAll(SaveArg<0>(&infoCb), testing::Return(ByMove(ndk::ScopedAStatus::ok()))));
auto result = mModule->tune(sel);
@@ -655,7 +746,9 @@
// expect a callback if it succeeds
EXPECT_TRUE(result.isOk());
- EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec);
+ EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
+ ProgramInfo infoCb = mCallback->getCurrentProgramInfo();
+
LOG(DEBUG) << "Current program info: " << infoCb.toString();
// it should tune exactly to what was requested
@@ -669,13 +762,13 @@
*
* Verifies that:
* - the method succeeds;
- * - the program info is changed within kTuneTimeoutSec;
+ * - the program info is changed within kTuneTimeoutMs;
* - works both directions and with or without skipping sub-channel.
*/
TEST_P(BroadcastRadioHalTest, Seek) {
LOG(DEBUG) << "Seek Test";
- EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, _).Times(AnyNumber());
+ mCallback->reset();
auto result = mModule->seek(/* in_directionUp= */ true, /* in_skipSubChannel= */ true);
@@ -685,14 +778,14 @@
}
EXPECT_TRUE(result.isOk());
- EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec);
+ EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
- EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, _).Times(AnyNumber());
+ mCallback->reset();
result = mModule->seek(/* in_directionUp= */ false, /* in_skipSubChannel= */ false);
EXPECT_TRUE(result.isOk());
- EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec);
+ EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
}
/**
@@ -720,13 +813,13 @@
*
* Verifies that:
* - the method succeeds or returns NOT_SUPPORTED;
- * - the program info is changed within kTuneTimeoutSec if the method succeeded;
+ * - the program info is changed within kTuneTimeoutMs if the method succeeded;
* - works both directions.
*/
TEST_P(BroadcastRadioHalTest, Step) {
LOG(DEBUG) << "Step Test";
- EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, _).Times(AnyNumber());
+ mCallback->reset();
auto result = mModule->step(/* in_directionUp= */ true);
@@ -735,14 +828,14 @@
return;
}
EXPECT_TRUE(result.isOk());
- EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec);
+ EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
- EXPECT_TIMEOUT_CALL(*mCallback, onCurrentProgramInfoChangedMock, _).Times(AnyNumber());
+ mCallback->reset();
result = mModule->step(/* in_directionUp= */ false);
EXPECT_TRUE(result.isOk());
- EXPECT_TIMEOUT_CALL_WAIT(*mCallback, onCurrentProgramInfoChangedMock, kTuneTimeoutSec);
+ EXPECT_TRUE(mCallback->waitOnCurrentProgramInfoChangedCallback());
}
/**
@@ -955,7 +1048,7 @@
*
* Verifies that:
* - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
- * - the complete list is fetched within kProgramListScanTimeoutSec;
+ * - the complete list is fetched within kProgramListScanTimeoutMs;
* - stopProgramListUpdates does not crash.
*/
TEST_P(BroadcastRadioHalTest, GetProgramListFromEmptyFilter) {
@@ -969,7 +1062,7 @@
*
* Verifies that:
* - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
- * - the complete list is fetched within kProgramListScanTimeoutSec;
+ * - the complete list is fetched within kProgramListScanTimeoutMs;
* - stopProgramListUpdates does not crash;
* - result for startProgramListUpdates using a filter with AMFM_FREQUENCY_KHZ value of the first
* AMFM program matches the expected result.
@@ -1017,7 +1110,7 @@
*
* Verifies that:
* - startProgramListUpdates either succeeds or returns NOT_SUPPORTED;
- * - the complete list is fetched within kProgramListScanTimeoutSec;
+ * - the complete list is fetched within kProgramListScanTimeoutMs;
* - stopProgramListUpdates does not crash;
* - result for startProgramListUpdates using a filter with DAB_ENSEMBLE value of the first DAB
* program matches the expected result.
diff --git a/compatibility_matrices/Android.bp b/compatibility_matrices/Android.bp
index b3ca293..712f28a 100644
--- a/compatibility_matrices/Android.bp
+++ b/compatibility_matrices/Android.bp
@@ -31,6 +31,7 @@
"kernel_config_q_4.14",
"kernel_config_q_4.19",
],
+ core_hals: "only",
}
vintf_compatibility_matrix {
@@ -44,6 +45,7 @@
"kernel_config_r_4.19",
"kernel_config_r_5.4",
],
+ core_hals: "only",
}
vintf_compatibility_matrix {
@@ -57,6 +59,7 @@
"kernel_config_s_5.4",
"kernel_config_s_5.10",
],
+ core_hals: "only",
}
vintf_compatibility_matrix {
@@ -69,6 +72,7 @@
"kernel_config_t_5.10",
"kernel_config_t_5.15",
],
+ core_hals: "only",
}
vintf_compatibility_matrix {
@@ -81,6 +85,7 @@
"kernel_config_u_5.15",
"kernel_config_u_6.1",
],
+ core_hals: "only",
}
vintf_compatibility_matrix {
@@ -93,4 +98,5 @@
"kernel_config_v_5.15",
"kernel_config_v_6.1",
],
+ core_hals: "only",
}
diff --git a/compatibility_matrices/build/vintf_compatibility_matrix.go b/compatibility_matrices/build/vintf_compatibility_matrix.go
index c72cbde..4f342b2 100644
--- a/compatibility_matrices/build/vintf_compatibility_matrix.go
+++ b/compatibility_matrices/build/vintf_compatibility_matrix.go
@@ -35,10 +35,10 @@
pctx = android.NewPackageContext("android/vintf")
assembleVintfRule = pctx.AndroidStaticRule("assemble_vintf", blueprint.RuleParams{
- Command: `${assembleVintfCmd} -i ${inputs} -o ${out}`,
+ Command: `${assembleVintfCmd} -i ${inputs} -o ${out} ${extraParams}`,
CommandDeps: []string{"${assembleVintfCmd}"},
Description: "assemble_vintf -i ${inputs}",
- }, "inputs")
+ }, "inputs", "extraParams")
xmllintXsd = pctx.AndroidStaticRule("xmllint-xsd", blueprint.RuleParams{
Command: `$XmlLintCmd --quiet --schema $xsd $in > /dev/null && touch -a $out`,
@@ -64,6 +64,13 @@
// list of kernel_config modules to be combined to final output
Kernel_configs []string
+
+ // Default is "default" for compatibility matrices on /vendor
+ // and /odm, and "disallow" for compatibility matrices on /system,
+ // /product, and /system_ext.
+ // If value is "only", only android.* HALs are allowed. If value
+ // is "disallow", none of android.* HALs are allowed.
+ Core_hals *string
}
type vintfCompatibilityMatrixRule struct {
@@ -166,7 +173,8 @@
Implicits: inputPaths,
Output: g.genFile,
Args: map[string]string{
- "inputs": strings.Join(inputPaths.Strings(), ":"),
+ "inputs": strings.Join(inputPaths.Strings(), ":"),
+ "extraParams": strings.Join(g.getExtraParams(), " "),
},
})
g.generateValidateBuildAction(ctx, g.genFile, schema.Path())
@@ -191,3 +199,23 @@
},
}
}
+
+// Return extra parameters to assemble_vintf.
+func (g *vintfCompatibilityMatrixRule) getExtraParams() []string {
+ var extraParams []string
+
+ coreHalsStrategy := proptools.StringDefault(
+ g.properties.Core_hals,
+ g.defaultCoreHalsStrategy(),
+ )
+ extraParams = append(extraParams, "--core-hals", proptools.ShellEscape(coreHalsStrategy))
+ return extraParams
+}
+
+func (g *vintfCompatibilityMatrixRule) defaultCoreHalsStrategy() string {
+ // TODO(b/290408770): default to "disallow" for FCMs
+
+ // For Device (vendor, odm) compatibility matrix, default is
+ // to not check anything.
+ return "default"
+}
diff --git a/compatibility_matrices/bump.py b/compatibility_matrices/bump.py
new file mode 100755
index 0000000..88b7a42
--- /dev/null
+++ b/compatibility_matrices/bump.py
@@ -0,0 +1,158 @@
+#!/usr/bin/env python3
+#
+# 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.
+#
+"""
+Creates the next compatibility matrix.
+
+Requires libvintf Level.h to be updated before executing this script.
+"""
+
+import argparse
+import os
+import pathlib
+import shutil
+import subprocess
+import textwrap
+
+
+def check_call(*args, **kwargs):
+ print(args)
+ subprocess.check_call(*args, **kwargs)
+
+
+def check_output(*args, **kwargs):
+ print(args)
+ return subprocess.check_output(*args, **kwargs)
+
+
+class Bump(object):
+
+ def __init__(self, cmdline_args):
+ self.top = pathlib.Path(os.environ["ANDROID_BUILD_TOP"])
+ self.interfaces_dir = self.top / "hardware/interfaces"
+
+ self.current_level = cmdline_args.current
+ self.current_module_name = f"framework_compatibility_matrix.{self.current_level}.xml"
+ self.current_xml = self.interfaces_dir / f"compatibility_matrices/compatibility_matrix.{self.current_level}.xml"
+
+ self.next_level = cmdline_args.next
+ self.next_module_name = f"framework_compatibility_matrix.{self.next_level}.xml"
+ self.next_xml = self.interfaces_dir / f"compatibility_matrices/compatibility_matrix.{self.next_level}.xml"
+
+ self.level_to_letter = self.get_level_to_letter_mapping()
+ print("Found level mapping in libvintf Level.h:", self.level_to_letter)
+
+ def run(self):
+ self.bump_kernel_configs()
+ self.copy_matrix()
+ self.edit_android_bp()
+ self.edit_android_mk()
+
+ def get_level_to_letter_mapping(self):
+ levels_file = self.top / "system/libvintf/include/vintf/Level.h"
+ with open(levels_file) as f:
+ lines = f.readlines()
+ pairs = [
+ line.split("=", maxsplit=2) for line in lines if "=" in line
+ ]
+ return {
+ level.strip().removesuffix(","): letter.strip()
+ for letter, level in pairs
+ }
+
+ def bump_kernel_configs(self):
+ check_call([
+ self.top / "kernel/configs/tools/bump.py",
+ self.level_to_letter[self.current_level].lower(),
+ self.level_to_letter[self.next_level].lower(),
+ ])
+
+ def copy_matrix(self):
+ shutil.copyfile(self.current_xml, self.next_xml)
+
+ def edit_android_bp(self):
+ android_bp = self.interfaces_dir / "compatibility_matrices/Android.bp"
+
+ with open(android_bp, "r+") as f:
+ if self.next_module_name not in f.read():
+ f.seek(0, 2) # end of file
+ f.write("\n")
+ f.write(
+ textwrap.dedent(f"""\
+ vintf_compatibility_matrix {{
+ name: "{self.next_module_name}",
+ }}
+ """))
+
+ next_kernel_configs = check_output(
+ """grep -rh name: | sed -E 's/^.*"(.*)".*/\\1/g'""",
+ cwd=self.top / "kernel/configs" /
+ self.level_to_letter[self.next_level].lower(),
+ text=True,
+ shell=True,
+ ).splitlines()
+ print(next_kernel_configs)
+
+ check_call([
+ "bpmodify", "-w", "-m", self.next_module_name, "-property", "stem",
+ "-str", self.next_xml.name, android_bp
+ ])
+
+ check_call([
+ "bpmodify", "-w", "-m", self.next_module_name, "-property", "srcs",
+ "-a",
+ self.next_xml.relative_to(android_bp.parent), android_bp
+ ])
+
+ check_call([
+ "bpmodify", "-w", "-m", self.next_module_name, "-property",
+ "kernel_configs", "-a", " ".join(next_kernel_configs), android_bp
+ ])
+
+ def edit_android_mk(self):
+ android_mk = self.interfaces_dir / "compatibility_matrices/Android.mk"
+ with open(android_mk) as f:
+ if self.next_module_name in f.read():
+ return
+ f.seek(0)
+ lines = f.readlines()
+ current_module_line_number = None
+ for line_number, line in enumerate(lines):
+ if self.current_module_name in line:
+ current_module_line_number = line_number
+ break
+ assert current_module_line_number is not None
+ lines.insert(current_module_line_number + 1,
+ f" {self.next_module_name} \\\n")
+ with open(android_mk, "w") as f:
+ f.write("".join(lines))
+
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument("current",
+ type=str,
+ help="VINTF level of the current version (e.g. 9)")
+ parser.add_argument("next",
+ type=str,
+ help="VINTF level of the next version (e.g. 10)")
+ cmdline_args = parser.parse_args()
+
+ Bump(cmdline_args).run()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/compatibility_matrices/compatibility_matrix.4.xml b/compatibility_matrices/compatibility_matrix.4.xml
index b9fb3f4..204b83b 100644
--- a/compatibility_matrices/compatibility_matrix.4.xml
+++ b/compatibility_matrices/compatibility_matrix.4.xml
@@ -361,6 +361,7 @@
<interface>
<name>ISap</name>
<instance>slot1</instance>
+ <instance>slot2</instance>
</interface>
</hal>
<hal format="hidl" optional="true">
diff --git a/compatibility_matrices/compatibility_matrix.5.xml b/compatibility_matrices/compatibility_matrix.5.xml
index b374c8c..bbf7055 100644
--- a/compatibility_matrices/compatibility_matrix.5.xml
+++ b/compatibility_matrices/compatibility_matrix.5.xml
@@ -399,6 +399,7 @@
<interface>
<name>ISap</name>
<instance>slot1</instance>
+ <instance>slot2</instance>
</interface>
</hal>
<hal format="hidl" optional="true">
diff --git a/compatibility_matrices/compatibility_matrix.6.xml b/compatibility_matrices/compatibility_matrix.6.xml
index 40ae655..1b812ed 100644
--- a/compatibility_matrices/compatibility_matrix.6.xml
+++ b/compatibility_matrices/compatibility_matrix.6.xml
@@ -454,6 +454,7 @@
<interface>
<name>ISap</name>
<instance>slot1</instance>
+ <instance>slot2</instance>
</interface>
</hal>
<hal format="hidl" optional="true">
diff --git a/compatibility_matrices/compatibility_matrix.7.xml b/compatibility_matrices/compatibility_matrix.7.xml
index e5ef954..4419796 100644
--- a/compatibility_matrices/compatibility_matrix.7.xml
+++ b/compatibility_matrices/compatibility_matrix.7.xml
@@ -582,6 +582,7 @@
<interface>
<name>ISap</name>
<instance>slot1</instance>
+ <instance>slot2</instance>
</interface>
</hal>
<hal format="hidl" optional="true">
diff --git a/compatibility_matrices/compatibility_matrix.9.xml b/compatibility_matrices/compatibility_matrix.9.xml
index 14b9210..559e7c2 100644
--- a/compatibility_matrices/compatibility_matrix.9.xml
+++ b/compatibility_matrices/compatibility_matrix.9.xml
@@ -248,7 +248,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.graphics.composer3</name>
- <version>2</version>
+ <version>3</version>
<interface>
<name>IComposer</name>
<instance>default</instance>
diff --git a/graphics/Android.bp b/graphics/Android.bp
index 2fbcb41..8a69f09 100644
--- a/graphics/Android.bp
+++ b/graphics/Android.bp
@@ -53,13 +53,13 @@
cc_defaults {
name: "android.hardware.graphics.composer3-ndk_static",
static_libs: [
- "android.hardware.graphics.composer3-V2-ndk",
+ "android.hardware.graphics.composer3-V3-ndk",
],
}
cc_defaults {
name: "android.hardware.graphics.composer3-ndk_shared",
shared_libs: [
- "android.hardware.graphics.composer3-V2-ndk",
+ "android.hardware.graphics.composer3-V3-ndk",
],
}
diff --git a/graphics/composer/2.4/vts/functional/AndroidTest.xml b/graphics/composer/2.4/vts/functional/AndroidTest.xml
index 773db93..7626995 100644
--- a/graphics/composer/2.4/vts/functional/AndroidTest.xml
+++ b/graphics/composer/2.4/vts/functional/AndroidTest.xml
@@ -31,6 +31,6 @@
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="VtsHalGraphicsComposerV2_4TargetTest" />
- <option name="native-test-timeout" value="900000"/>
+ <option name="native-test-timeout" value="1800000"/>
</test>
</configuration>
diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
index 35225d9..dac46f9 100644
--- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
+++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp
@@ -544,10 +544,12 @@
setActiveConfigWithConstraints(display, config2, constraints, &timeline));
EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos >= constraints.desiredTimeNanos);
- // Refresh rate should change within a reasonable time
- constexpr std::chrono::nanoseconds kReasonableTimeForChange = 1s; // 1 second
- EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos - constraints.desiredTimeNanos <=
- kReasonableTimeForChange.count());
+ if (configGroup1 == configGroup2) {
+ // Refresh rate should change within a reasonable time
+ constexpr std::chrono::nanoseconds kReasonableTimeForChange = 1s;
+ EXPECT_TRUE(timeline.newVsyncAppliedTimeNanos - constraints.desiredTimeNanos <=
+ kReasonableTimeForChange.count());
+ }
if (timeline.refreshRequired) {
if (params.refreshMiss) {
diff --git a/graphics/composer/aidl/Android.bp b/graphics/composer/aidl/Android.bp
index 40448ec..88abb73 100644
--- a/graphics/composer/aidl/Android.bp
+++ b/graphics/composer/aidl/Android.bp
@@ -31,7 +31,7 @@
enabled: true,
support_system_process: true,
},
- frozen: true,
+ frozen: false,
vndk_use_version: "1",
srcs: [
"android/hardware/graphics/composer3/*.aidl",
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayConfiguration.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayConfiguration.aidl
new file mode 100644
index 0000000..908842a
--- /dev/null
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/DisplayConfiguration.aidl
@@ -0,0 +1,47 @@
+/**
+ * Copyright 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.graphics.composer3;
+@VintfStability
+parcelable DisplayConfiguration {
+ int configId;
+ int width;
+ int height;
+ @nullable android.hardware.graphics.composer3.DisplayConfiguration.Dpi dpi;
+ int configGroup;
+ int vsyncPeriod;
+ parcelable Dpi {
+ float x;
+ float y;
+ }
+}
diff --git a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
index cb85a88..2f08b6f 100644
--- a/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
+++ b/graphics/composer/aidl/aidl_api/android.hardware.graphics.composer3/current/android/hardware/graphics/composer3/IComposerClient.aidl
@@ -44,6 +44,9 @@
float[] getDataspaceSaturationMatrix(android.hardware.graphics.common.Dataspace dataspace);
int getDisplayAttribute(long display, int config, android.hardware.graphics.composer3.DisplayAttribute attribute);
android.hardware.graphics.composer3.DisplayCapability[] getDisplayCapabilities(long display);
+ /**
+ * @deprecated use getDisplayConfigurations instead. For legacy support getDisplayConfigs should return at least one valid config. All the configs returned from the getDisplayConfigs should also be returned from getDisplayConfigurations.
+ */
int[] getDisplayConfigs(long display);
android.hardware.graphics.composer3.DisplayConnectionType getDisplayConnectionType(long display);
android.hardware.graphics.composer3.DisplayIdentification getDisplayIdentificationData(long display);
@@ -79,6 +82,7 @@
android.hardware.graphics.common.HdrConversionCapability[] getHdrConversionCapabilities();
android.hardware.graphics.common.Hdr setHdrConversionStrategy(in android.hardware.graphics.common.HdrConversionStrategy conversionStrategy);
void setRefreshRateChangedCallbackDebugEnabled(long display, boolean enabled);
+ android.hardware.graphics.composer3.DisplayConfiguration[] getDisplayConfigurations(long display);
const int EX_BAD_CONFIG = 1;
const int EX_BAD_DISPLAY = 2;
const int EX_BAD_LAYER = 3;
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayConfiguration.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayConfiguration.aidl
new file mode 100644
index 0000000..b0095d2
--- /dev/null
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/DisplayConfiguration.aidl
@@ -0,0 +1,63 @@
+/**
+ * Copyright 2023, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.graphics.composer3;
+
+@VintfStability
+parcelable DisplayConfiguration {
+ /**
+ * The config id, to be used with IComposerClient.setActiveConfig.
+ */
+ int configId;
+
+ /**
+ * Dimensions in pixels
+ */
+ int width;
+ int height;
+
+ /**
+ * Dots per thousand inches.
+ * If the DPI for a configuration is unavailable or is
+ * considered unreliable, the device may set null instead.
+ */
+ parcelable Dpi {
+ float x;
+ float y;
+ }
+ @nullable Dpi dpi;
+
+ /**
+ * The configuration group ID this config is associated to.
+ * Switching between configurations within the same group may be
+ * done seamlessly in some conditions via
+ * setActiveConfigWithConstraints. Configurations which share the
+ * same config group are similar in all attributes except for the
+ * vsync period.
+ */
+ int configGroup;
+
+ /**
+ * Vsync period in nanoseconds. This period represents the internal
+ * frequency of the display. IComposerCallback.onVsync is expected
+ * to be called on each vsync event. For non-VRR configurations, a
+ * frame can be presented on each vsync event.
+ *
+ * A present fence, retrieved from CommandResultPayload.presentFence
+ * must be signaled on a vsync boundary.
+ */
+ int vsyncPeriod;
+}
diff --git a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
index 4e77f86..5d04a28 100644
--- a/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
+++ b/graphics/composer/aidl/android/hardware/graphics/composer3/IComposerClient.aidl
@@ -28,6 +28,7 @@
import android.hardware.graphics.composer3.DisplayAttribute;
import android.hardware.graphics.composer3.DisplayCapability;
import android.hardware.graphics.composer3.DisplayCommand;
+import android.hardware.graphics.composer3.DisplayConfiguration;
import android.hardware.graphics.composer3.DisplayConnectionType;
import android.hardware.graphics.composer3.DisplayContentSample;
import android.hardware.graphics.composer3.DisplayContentSamplingAttributes;
@@ -263,15 +264,12 @@
DisplayCapability[] getDisplayCapabilities(long display);
/**
- * Returns handles for all of the valid display configurations on this
- * display.
- * This should never return INVALID_CONFIGURATION as a valid value.
+ * @deprecated use getDisplayConfigurations instead.
+ * For legacy support getDisplayConfigs should return at least one valid config.
+ * All the configs returned from the getDisplayConfigs should also be returned
+ * from getDisplayConfigurations.
*
- * @param display is the display to query.
- *
- * @return is an array of configuration handles.
- *
- * @exception EX_BAD_DISPLAY when an invalid display handle was passed in.
+ * @see getDisplayConfigurations
*/
int[] getDisplayConfigs(long display);
@@ -864,4 +862,15 @@
* false when refresh rate callback is disabled.
*/
void setRefreshRateChangedCallbackDebugEnabled(long display, boolean enabled);
+
+ /**
+ * Returns all of the valid display configurations.
+ * getDisplayConfigurations is the superset of getDisplayConfigs and
+ * getDisplayConfigs should return at least one config.
+ *
+ * @param display is the display for which the configurations are requested.
+ *
+ * @see getDisplayConfigs
+ */
+ DisplayConfiguration[] getDisplayConfigurations(long display);
}
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.cpp b/graphics/composer/aidl/vts/VtsComposerClient.cpp
index 25b0ca0..bf42d88 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.cpp
+++ b/graphics/composer/aidl/vts/VtsComposerClient.cpp
@@ -58,7 +58,7 @@
return verifyComposerCallbackParams() && destroyAllLayers();
}
-std::pair<ScopedAStatus, int32_t> VtsComposerClient::getInterfaceVersion() {
+std::pair<ScopedAStatus, int32_t> VtsComposerClient::getInterfaceVersion() const {
int32_t version = 1;
auto status = mComposerClient->getInterfaceVersion(&version);
return {std::move(status), version};
@@ -295,7 +295,24 @@
std::pair<ScopedAStatus, std::vector<int32_t>> VtsComposerClient::getDisplayConfigs(
int64_t display) {
std::vector<int32_t> outConfigs;
- return {mComposerClient->getDisplayConfigs(display, &outConfigs), outConfigs};
+ if (!getDisplayConfigurationSupported()) {
+ return {mComposerClient->getDisplayConfigs(display, &outConfigs), outConfigs};
+ }
+
+ auto [status, configs] = getDisplayConfigurations(display);
+ if (!status.isOk()) {
+ return {std::move(status), outConfigs};
+ }
+ for (const auto& config : configs) {
+ outConfigs.emplace_back(config.configId);
+ }
+ return {std::move(status), outConfigs};
+}
+
+std::pair<ScopedAStatus, std::vector<DisplayConfiguration>>
+VtsComposerClient::getDisplayConfigurations(int64_t display) {
+ std::vector<DisplayConfiguration> outConfigs;
+ return {mComposerClient->getDisplayConfigurations(display, &outConfigs), outConfigs};
}
std::pair<ScopedAStatus, int32_t> VtsComposerClient::getDisplayVsyncPeriod(int64_t display) {
@@ -439,31 +456,41 @@
vtsDisplays.reserve(displays.size());
for (int64_t display : displays) {
auto vtsDisplay = VtsDisplay{display};
- auto configs = getDisplayConfigs(display);
- if (!configs.first.isOk()) {
- ALOGE("Unable to get the displays for test, failed to get the configs "
- "for display %" PRId64,
- display);
- return {std::move(configs.first), vtsDisplays};
- }
- for (int config : configs.second) {
- auto status = addDisplayConfig(&vtsDisplay, config);
+ if (getDisplayConfigurationSupported()) {
+ auto [status, configs] = getDisplayConfigurations(display);
if (!status.isOk()) {
- ALOGE("Unable to get the displays for test, failed to add config "
+ ALOGE("Unable to get the displays for test, failed to get the DisplayConfigs "
"for display %" PRId64,
display);
return {std::move(status), vtsDisplays};
}
+ addDisplayConfigs(&vtsDisplay, configs);
+ } else {
+ auto [status, configs] = getDisplayConfigs(display);
+ if (!status.isOk()) {
+ ALOGE("Unable to get the displays for test, failed to get the configs "
+ "for display %" PRId64,
+ display);
+ return {std::move(status), vtsDisplays};
+ }
+ for (int config : configs) {
+ status = addDisplayConfigLegacy(&vtsDisplay, config);
+ if (!status.isOk()) {
+ ALOGE("Unable to get the displays for test, failed to add config "
+ "for display %" PRId64,
+ display);
+ return {std::move(status), vtsDisplays};
+ }
+ }
}
-
- auto config = getActiveConfig(display);
- if (!config.first.isOk()) {
+ auto activeConfig = getActiveConfig(display);
+ if (!activeConfig.first.isOk()) {
ALOGE("Unable to get the displays for test, failed to get active config "
- "for display %" PRId64, display);
- return {std::move(config.first), vtsDisplays};
+ "for display %" PRId64,
+ display);
+ return {std::move(activeConfig.first), vtsDisplays};
}
-
- auto status = updateDisplayProperties(&vtsDisplay, config.second);
+ auto status = updateDisplayProperties(&vtsDisplay, activeConfig.second);
if (!status.isOk()) {
ALOGE("Unable to get the displays for test, "
"failed to update the properties "
@@ -480,39 +507,53 @@
}
}
-ScopedAStatus VtsComposerClient::addDisplayConfig(VtsDisplay* vtsDisplay, int32_t config) {
- const auto width =
- getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::WIDTH);
- const auto height =
- getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::HEIGHT);
+void VtsComposerClient::addDisplayConfigs(VtsDisplay* vtsDisplay,
+ const std::vector<DisplayConfiguration>& configs) {
+ for (const auto& config : configs) {
+ vtsDisplay->addDisplayConfig(config.configId, {config.vsyncPeriod, config.configGroup});
+ }
+}
+
+ScopedAStatus VtsComposerClient::addDisplayConfigLegacy(VtsDisplay* vtsDisplay, int32_t config) {
const auto vsyncPeriod =
getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::VSYNC_PERIOD);
const auto configGroup =
getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::CONFIG_GROUP);
- if (width.first.isOk() && height.first.isOk() && vsyncPeriod.first.isOk() &&
- configGroup.first.isOk()) {
+ if (vsyncPeriod.first.isOk() && configGroup.first.isOk()) {
vtsDisplay->addDisplayConfig(config, {vsyncPeriod.second, configGroup.second});
return ScopedAStatus::ok();
}
- LOG(ERROR) << "Failed to update display property for width: " << width.first.isOk()
- << ", height: " << height.first.isOk() << ", vsync: " << vsyncPeriod.first.isOk()
+ LOG(ERROR) << "Failed to update display property vsync: " << vsyncPeriod.first.isOk()
<< ", config: " << configGroup.first.isOk();
return ScopedAStatus::fromServiceSpecificError(IComposerClient::EX_BAD_CONFIG);
}
ScopedAStatus VtsComposerClient::updateDisplayProperties(VtsDisplay* vtsDisplay, int32_t config) {
- const auto width =
- getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::WIDTH);
- const auto height =
- getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::HEIGHT);
- if (width.first.isOk() && height.first.isOk()) {
- vtsDisplay->setDimensions(width.second, height.second);
- return ScopedAStatus::ok();
- }
+ if (getDisplayConfigurationSupported()) {
+ auto [status, configs] = getDisplayConfigurations(vtsDisplay->getDisplayId());
+ if (status.isOk()) {
+ for (const auto& displayConfig : configs) {
+ if (displayConfig.configId == config) {
+ vtsDisplay->setDimensions(displayConfig.width, displayConfig.height);
+ return ScopedAStatus::ok();
+ }
+ }
+ }
+ LOG(ERROR) << "Failed to update display property with DisplayConfig";
+ } else {
+ const auto width =
+ getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::WIDTH);
+ const auto height =
+ getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::HEIGHT);
+ if (width.first.isOk() && height.first.isOk()) {
+ vtsDisplay->setDimensions(width.second, height.second);
+ return ScopedAStatus::ok();
+ }
- LOG(ERROR) << "Failed to update display property for width: " << width.first.isOk()
- << ", height: " << height.first.isOk();
+ LOG(ERROR) << "Failed to update display property for width: " << width.first.isOk()
+ << ", height: " << height.first.isOk();
+ }
return ScopedAStatus::fromServiceSpecificError(IComposerClient::EX_BAD_CONFIG);
}
@@ -576,6 +617,13 @@
return isValid;
}
+bool VtsComposerClient::getDisplayConfigurationSupported() const {
+ auto [status, interfaceVersion] = getInterfaceVersion();
+ EXPECT_TRUE(status.isOk());
+ // getDisplayConfigurations api is supported starting interface version 3
+ return interfaceVersion >= 3;
+}
+
bool VtsComposerClient::destroyAllLayers() {
std::unordered_map<int64_t, DisplayResource> physicalDisplays;
while (!mDisplayResources.empty()) {
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.h b/graphics/composer/aidl/vts/VtsComposerClient.h
index ea3318c..1add23c 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.h
+++ b/graphics/composer/aidl/vts/VtsComposerClient.h
@@ -61,7 +61,7 @@
bool tearDown();
- std::pair<ScopedAStatus, int32_t> getInterfaceVersion();
+ std::pair<ScopedAStatus, int32_t> getInterfaceVersion() const;
std::pair<ScopedAStatus, VirtualDisplay> createVirtualDisplay(int32_t width, int32_t height,
PixelFormat pixelFormat,
@@ -142,6 +142,9 @@
std::pair<ScopedAStatus, std::vector<int32_t>> getDisplayConfigs(int64_t display);
+ std::pair<ScopedAStatus, std::vector<DisplayConfiguration>> getDisplayConfigurations(
+ int64_t display);
+
std::pair<ScopedAStatus, int32_t> getDisplayVsyncPeriod(int64_t display);
ScopedAStatus setAutoLowLatencyMode(int64_t display, bool isEnabled);
@@ -190,7 +193,9 @@
std::vector<RefreshRateChangedDebugData> takeListOfRefreshRateChangedDebugData();
private:
- ScopedAStatus addDisplayConfig(VtsDisplay* vtsDisplay, int32_t config);
+ void addDisplayConfigs(VtsDisplay*, const std::vector<DisplayConfiguration>&);
+ ScopedAStatus addDisplayConfigLegacy(VtsDisplay*, int32_t config);
+ bool getDisplayConfigurationSupported() const;
ScopedAStatus updateDisplayProperties(VtsDisplay* vtsDisplay, int32_t config);
ScopedAStatus addDisplayToDisplayResources(int64_t display, bool isVirtual);
diff --git a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
index bbcd36f..d559213 100644
--- a/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
+++ b/graphics/composer/aidl/vts/VtsHalGraphicsComposer3_TargetTest.cpp
@@ -1208,6 +1208,110 @@
}
}
+class GraphicsComposerAidlV3Test : public GraphicsComposerAidlTest {
+ protected:
+ void SetUp() override {
+ GraphicsComposerAidlTest::SetUp();
+ if (getInterfaceVersion() <= 2) {
+ GTEST_SKIP() << "Device interface version is expected to be >= 3";
+ }
+ }
+};
+
+TEST_P(GraphicsComposerAidlV3Test, GetDisplayConfigurations) {
+ for (const auto& display : mDisplays) {
+ const auto& [status, displayConfigurations] =
+ mComposerClient->getDisplayConfigurations(display.getDisplayId());
+ EXPECT_TRUE(status.isOk());
+ EXPECT_FALSE(displayConfigurations.empty());
+
+ for (const auto& displayConfig : displayConfigurations) {
+ EXPECT_NE(-1, displayConfig.width);
+ EXPECT_NE(-1, displayConfig.height);
+ EXPECT_NE(-1, displayConfig.vsyncPeriod);
+ EXPECT_NE(-1, displayConfig.configGroup);
+ if (displayConfig.dpi) {
+ EXPECT_NE(-1, displayConfig.dpi->x);
+ EXPECT_NE(-1, displayConfig.dpi->y);
+ }
+ }
+ }
+}
+
+TEST_P(GraphicsComposerAidlV3Test, GetDisplayConfigsIsSubsetOfGetDisplayConfigurations) {
+ for (const auto& display : mDisplays) {
+ const auto& [status, displayConfigurations] =
+ mComposerClient->getDisplayConfigurations(display.getDisplayId());
+ EXPECT_TRUE(status.isOk());
+
+ const auto& [legacyConfigStatus, legacyConfigs] =
+ mComposerClient->getDisplayConfigs(display.getDisplayId());
+ EXPECT_TRUE(legacyConfigStatus.isOk());
+ EXPECT_FALSE(legacyConfigs.empty());
+ EXPECT_TRUE(legacyConfigs.size() <= displayConfigurations.size());
+
+ for (const auto legacyConfigId : legacyConfigs) {
+ const auto& legacyWidth = mComposerClient->getDisplayAttribute(
+ display.getDisplayId(), legacyConfigId, DisplayAttribute::WIDTH);
+ const auto& legacyHeight = mComposerClient->getDisplayAttribute(
+ display.getDisplayId(), legacyConfigId, DisplayAttribute::HEIGHT);
+ const auto& legacyVsyncPeriod = mComposerClient->getDisplayAttribute(
+ display.getDisplayId(), legacyConfigId, DisplayAttribute::VSYNC_PERIOD);
+ const auto& legacyConfigGroup = mComposerClient->getDisplayAttribute(
+ display.getDisplayId(), legacyConfigId, DisplayAttribute::CONFIG_GROUP);
+ const auto& legacyDpiX = mComposerClient->getDisplayAttribute(
+ display.getDisplayId(), legacyConfigId, DisplayAttribute::DPI_X);
+ const auto& legacyDpiY = mComposerClient->getDisplayAttribute(
+ display.getDisplayId(), legacyConfigId, DisplayAttribute::DPI_Y);
+
+ EXPECT_TRUE(legacyWidth.first.isOk() && legacyHeight.first.isOk() &&
+ legacyVsyncPeriod.first.isOk() && legacyConfigGroup.first.isOk());
+
+ EXPECT_TRUE(std::any_of(
+ displayConfigurations.begin(), displayConfigurations.end(),
+ [&](const auto& displayConfiguration) {
+ const bool requiredAttributesPredicate =
+ displayConfiguration.configId == legacyConfigId &&
+ displayConfiguration.width == legacyWidth.second &&
+ displayConfiguration.height == legacyHeight.second &&
+ displayConfiguration.vsyncPeriod == legacyVsyncPeriod.second &&
+ displayConfiguration.configGroup == legacyConfigGroup.second;
+
+ if (!requiredAttributesPredicate) {
+ // Required attributes did not match
+ return false;
+ }
+
+ // Check optional attributes
+ const auto& [legacyDpiXStatus, legacyDpiXValue] = legacyDpiX;
+ const auto& [legacyDpiYStatus, legacyDpiYValue] = legacyDpiY;
+ if (displayConfiguration.dpi) {
+ if (!legacyDpiXStatus.isOk() || !legacyDpiYStatus.isOk()) {
+ // getDisplayAttribute failed for optional attributes
+ return false;
+ }
+
+ // DPI values in DisplayConfigurations are not scaled (* 1000.f)
+ // the way they are in the legacy DisplayConfigs.
+ constexpr float kEpsilon = 0.001f;
+ return std::abs(displayConfiguration.dpi->x -
+ legacyDpiXValue / 1000.f) < kEpsilon &&
+ std::abs(displayConfiguration.dpi->y -
+ legacyDpiYValue / 1000.f) < kEpsilon;
+ } else {
+ return !legacyDpiXStatus.isOk() && !legacyDpiYStatus.isOk() &&
+ EX_SERVICE_SPECIFIC == legacyDpiXStatus.getExceptionCode() &&
+ EX_SERVICE_SPECIFIC == legacyDpiYStatus.getExceptionCode() &&
+ IComposerClient::EX_UNSUPPORTED ==
+ legacyDpiXStatus.getServiceSpecificError() &&
+ IComposerClient::EX_UNSUPPORTED ==
+ legacyDpiYStatus.getServiceSpecificError();
+ }
+ }));
+ }
+ }
+}
+
// Tests for Command.
class GraphicsComposerAidlCommandTest : public GraphicsComposerAidlTest {
protected:
@@ -2641,6 +2745,11 @@
PerInstance, GraphicsComposerAidlV2Test,
testing::ValuesIn(::android::getAidlHalInstanceNames(IComposer::descriptor)),
::android::PrintInstanceNameToString);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerAidlV3Test);
+INSTANTIATE_TEST_SUITE_P(
+ PerInstance, GraphicsComposerAidlV3Test,
+ testing::ValuesIn(::android::getAidlHalInstanceNames(IComposer::descriptor)),
+ ::android::PrintInstanceNameToString);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(GraphicsComposerAidlCommandV2Test);
INSTANTIATE_TEST_SUITE_P(
PerInstance, GraphicsComposerAidlCommandV2Test,
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
index cbc1e30..d1a831b 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetwork.aidl
@@ -82,4 +82,5 @@
oneway void isNullCipherAndIntegrityEnabled(in int serial);
oneway void isN1ModeEnabled(in int serial);
oneway void setN1ModeEnabled(in int serial, boolean enable);
+ oneway void setSatellitePlmn(in int serial, in List<String> plmnList);
}
diff --git a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
index c86bebc..bf43d7c 100644
--- a/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio.network/current/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -81,4 +81,5 @@
oneway void isNullCipherAndIntegrityEnabledResponse(in android.hardware.radio.RadioResponseInfo info, in boolean isEnabled);
oneway void isN1ModeEnabledResponse(in android.hardware.radio.RadioResponseInfo info, boolean isEnabled);
oneway void setN1ModeEnabledResponse(in android.hardware.radio.RadioResponseInfo info);
+ oneway void setSatellitePlmnResponse(in android.hardware.radio.RadioResponseInfo info);
}
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
index e4c3856..2f40bd6 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetwork.aidl
@@ -556,4 +556,18 @@
* Response function is IRadioNetworkResponse.setN1ModeEnabledResponse()
*/
void setN1ModeEnabled(in int serial, boolean enable);
+
+ /**
+ * Set the non-terrestrial PLMN with lower priority than terrestrial networks.
+ * MCC/MNC broadcast by the non-terrestrial networks may not be included in OPLMNwACT file on
+ * SIM profile. Acquisition of satellite based system is lower priority to terrestrial
+ * networks. UE shall make all attempts to acquire terrestrial service prior to camping on
+ * satellite LTE service.
+ *
+ * @param serial Serial number of request.
+ * @param plmnList The list of roaming PLMN used for connecting to satellite networks.
+ *
+ * Response function is IRadioNetworkResponse.setSatellitePlmnResponse()
+ */
+ void setSatellitePlmn(in int serial, in List<String> plmnList);
}
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
index db37a0e..9798944 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -668,4 +668,21 @@
* RadioError:INVALID_STATE
*/
void setN1ModeEnabledResponse(in RadioResponseInfo info);
+
+ /**
+ * Response of setSatellitePlmn.
+ * This is an optional API.
+ *
+ * @param info Response info struct containing response type, serial no. and error.
+ *
+ * Valid errors returned:
+ * RadioError:NONE
+ * RadioError:INVALID_ARGUMENTS
+ * RadioError:INVALID_MODEM_STATE
+ * RadioError:MODEM_ERR
+ * RadioError:NO_RESOURCES
+ * RadioError:RADIO_NOT_AVAILABLE
+ * RadioError:REQUEST_NOT_SUPPORTED
+ */
+ void setSatellitePlmnResponse(in RadioResponseInfo info);
}
diff --git a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
index d57c83d..ff3f10d 100644
--- a/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
+++ b/radio/aidl/compat/libradiocompat/include/libradiocompat/RadioNetwork.h
@@ -108,6 +108,9 @@
::ndk::ScopedAStatus setNullCipherAndIntegrityEnabled(int32_t serial, bool enabled) override;
::ndk::ScopedAStatus isNullCipherAndIntegrityEnabled(int32_t serial) override;
+ ::ndk::ScopedAStatus setSatellitePlmn(int32_t serial,
+ const std::vector<std::string>& plmnList) override;
+
protected:
std::shared_ptr<::aidl::android::hardware::radio::network::IRadioNetworkResponse> respond();
diff --git a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
index a379eec..1aa7c29 100644
--- a/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
+++ b/radio/aidl/compat/libradiocompat/network/RadioNetwork.cpp
@@ -372,4 +372,12 @@
respond()->setN1ModeEnabledResponse(notSupported(serial));
return ok();
}
+
+ScopedAStatus RadioNetwork::setSatellitePlmn(int32_t serial,
+ const std::vector<std::string>& /*plmnList*/) {
+ LOG_CALL << serial;
+ LOG(ERROR) << " setSatellitePlmn is unsupported by HIDL HALs";
+ respond()->setSatellitePlmnResponse(notSupported(serial));
+ return ok();
+}
} // namespace android::hardware::radio::compat
diff --git a/radio/aidl/vts/radio_network_response.cpp b/radio/aidl/vts/radio_network_response.cpp
index 25d45a5..eab9fac 100644
--- a/radio/aidl/vts/radio_network_response.cpp
+++ b/radio/aidl/vts/radio_network_response.cpp
@@ -320,3 +320,9 @@
parent_network.notify(info.serial);
return ndk::ScopedAStatus::ok();
}
+
+ndk::ScopedAStatus RadioNetworkResponse::setSatellitePlmnResponse(const RadioResponseInfo& info) {
+ rspInfo = info;
+ parent_network.notify(info.serial);
+ return ndk::ScopedAStatus::ok();
+}
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index 2beb249..9af2494 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -2076,3 +2076,37 @@
{RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE,
RadioError::MODEM_ERR, RadioError::REQUEST_NOT_SUPPORTED}));
}
+
+/**
+ * Test IRadioNetwork.setSatellitePlmn() for the response returned.
+ */
+TEST_P(RadioNetworkTest, setSatellitePlmn) {
+ int32_t aidl_version;
+ std::vector<std::string> plmnList = {"00101", "00102", "00103"};
+ ndk::ScopedAStatus aidl_status = radio_network->getInterfaceVersion(&aidl_version);
+ ASSERT_OK(aidl_status);
+ if (aidl_version < 3) {
+ ALOGI("Skipped the test since setSatellitePlmn is not supported on version < 3.");
+ GTEST_SKIP();
+ }
+
+ serial = GetRandomSerialNumber();
+
+ ndk::ScopedAStatus res = radio_network->setSatellitePlmn(serial, plmnList);
+ ASSERT_OK(res);
+
+ EXPECT_EQ(std::cv_status::no_timeout, wait());
+ EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
+ EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
+
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+ {
+ RadioError::NONE,
+ RadioError::INVALID_ARGUMENTS,
+ RadioError::INVALID_MODEM_STATE,
+ RadioError::MODEM_ERR,
+ RadioError::NO_RESOURCES,
+ RadioError::RADIO_NOT_AVAILABLE,
+ RadioError::REQUEST_NOT_SUPPORTED,
+ }));
+}
diff --git a/radio/aidl/vts/radio_network_utils.h b/radio/aidl/vts/radio_network_utils.h
index 8f8f6b0..c2466ac 100644
--- a/radio/aidl/vts/radio_network_utils.h
+++ b/radio/aidl/vts/radio_network_utils.h
@@ -169,6 +169,8 @@
const RadioResponseInfo& info, bool isEnabled) override;
virtual ndk::ScopedAStatus setN1ModeEnabledResponse(const RadioResponseInfo& info) override;
+
+ virtual ndk::ScopedAStatus setSatellitePlmnResponse(const RadioResponseInfo& info) override;
};
/* Callback class for radio network indication */
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
index 0499079..8a8eaa4 100644
--- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -89,6 +89,29 @@
return imei;
}
+// Use `ro.product.<property>_for_attestation` property for attestation if it is present else
+// fallback to use `ro.product.vendor.<property>` if it is present else fallback to
+// `ro.product.<property>`. Similar logic can be seen in Java method `getVendorDeviceIdProperty`
+// in frameworks/base/core/java/android/os/Build.java.
+template <Tag tag>
+void add_attestation_id(AuthorizationSetBuilder* attestation_id_tags,
+ TypedTag<TagType::BYTES, tag> tag_type, const char* prop) {
+ ::android::String8 prop_name =
+ ::android::String8::format("ro.product.%s_for_attestation", prop);
+ std::string prop_value = ::android::base::GetProperty(prop_name.string(), /* default= */ "");
+ if (!prop_value.empty()) {
+ add_tag_from_prop(attestation_id_tags, tag_type, prop_name.string());
+ } else {
+ prop_name = ::android::String8::format("ro.product.vendor.%s", prop);
+ prop_value = ::android::base::GetProperty(prop_name.string(), /* default= */ "");
+ if (!prop_value.empty()) {
+ add_tag_from_prop(attestation_id_tags, tag_type, prop_name.string());
+ } else {
+ prop_name = ::android::String8::format("ro.product.%s", prop);
+ add_tag_from_prop(attestation_id_tags, tag_type, prop_name.string());
+ }
+ }
+}
} // namespace
class AttestKeyTest : public KeyMintAidlTestBase {
@@ -798,11 +821,6 @@
}
TEST_P(AttestKeyTest, EcdsaAttestationID) {
- if (is_gsi_image()) {
- // GSI sets up a standard set of device identifiers that may not match
- // the device identifiers held by the device.
- GTEST_SKIP() << "Test not applicable under GSI";
- }
// Create attestation key.
AttestationKey attest_key;
vector<KeyCharacteristics> attest_key_characteristics;
@@ -822,39 +840,12 @@
// Collection of valid attestation ID tags.
auto attestation_id_tags = AuthorizationSetBuilder();
- // Use ro.product.brand_for_attestation property for attestation if it is present else fallback
- // to ro.product.brand
- std::string prop_value =
- ::android::base::GetProperty("ro.product.brand_for_attestation", /* default= */ "");
- if (!prop_value.empty()) {
- add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND,
- "ro.product.brand_for_attestation");
- } else {
- add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "ro.product.brand");
- }
- add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "ro.product.device");
- // Use ro.product.name_for_attestation property for attestation if it is present else fallback
- // to ro.product.name
- prop_value = ::android::base::GetProperty("ro.product.name_for_attestation", /* default= */ "");
- if (!prop_value.empty()) {
- add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT,
- "ro.product.name_for_attestation");
- } else {
- add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "ro.product.name");
- }
+ add_attestation_id(&attestation_id_tags, TAG_ATTESTATION_ID_BRAND, "brand");
+ add_attestation_id(&attestation_id_tags, TAG_ATTESTATION_ID_DEVICE, "device");
+ add_attestation_id(&attestation_id_tags, TAG_ATTESTATION_ID_PRODUCT, "name");
+ add_attestation_id(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER, "manufacturer");
+ add_attestation_id(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "model");
add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_SERIAL, "ro.serialno");
- add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MANUFACTURER,
- "ro.product.manufacturer");
- // Use ro.product.model_for_attestation property for attestation if it is present else fallback
- // to ro.product.model
- prop_value =
- ::android::base::GetProperty("ro.product.model_for_attestation", /* default= */ "");
- if (!prop_value.empty()) {
- add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL,
- "ro.product.model_for_attestation");
- } else {
- add_tag_from_prop(&attestation_id_tags, TAG_ATTESTATION_ID_MODEL, "ro.product.model");
- }
string imei = get_imei(0);
if (!imei.empty()) {
@@ -955,12 +946,6 @@
}
TEST_P(AttestKeyTest, SecondIMEIAttestationIDSuccess) {
- if (is_gsi_image()) {
- // GSI sets up a standard set of device identifiers that may not match
- // the device identifiers held by the device.
- GTEST_SKIP() << "Test not applicable under GSI";
- }
-
// Skip the test if there is no second IMEI exists.
string second_imei = get_imei(1);
if (second_imei.empty()) {
@@ -1029,12 +1014,6 @@
}
TEST_P(AttestKeyTest, MultipleIMEIAttestationIDSuccess) {
- if (is_gsi_image()) {
- // GSI sets up a standard set of device identifiers that may not match
- // the device identifiers held by the device.
- GTEST_SKIP() << "Test not applicable under GSI";
- }
-
// Skip the test if there is no first IMEI exists.
string imei = get_imei(0);
if (imei.empty()) {
diff --git a/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl b/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl
index e4d4cbe..607ceb3 100644
--- a/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl
+++ b/threadnetwork/aidl/aidl_api/android.hardware.threadnetwork/current/android/hardware/threadnetwork/IThreadChip.aidl
@@ -36,10 +36,9 @@
interface IThreadChip {
void open(in android.hardware.threadnetwork.IThreadChipCallback callback);
void close();
- void reset();
+ void hardwareReset();
void sendSpinelFrame(in byte[] frame);
const int ERROR_FAILED = 1;
- const int ERROR_INVALID_ARGS = 2;
- const int ERROR_NO_BUFS = 3;
- const int ERROR_BUSY = 4;
+ const int ERROR_NO_BUFS = 2;
+ const int ERROR_BUSY = 3;
}
diff --git a/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl b/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
index eebaa46..e695623 100644
--- a/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
+++ b/threadnetwork/aidl/android/hardware/threadnetwork/IThreadChip.aidl
@@ -30,19 +30,14 @@
const int ERROR_FAILED = 1;
/**
- * The invalid arguments.
- */
- const int ERROR_INVALID_ARGS = 2;
-
- /**
* Insufficient buffers available to send frames.
*/
- const int ERROR_NO_BUFS = 3;
+ const int ERROR_NO_BUFS = 2;
/**
* Service is busy and could not service the operation.
*/
- const int ERROR_BUSY = 4;
+ const int ERROR_BUSY = 3;
/**
* This method initializes the Thread HAL instance. If open completes
@@ -51,9 +46,10 @@
*
* @param callback A IThreadChipCallback callback instance.
*
+ * @throws EX_ILLEGAL_ARGUMENT if the callback handle is invalid (for example, it is null).
+ *
* @throws ServiceSpecificException with one of the following values:
* - ERROR_FAILED The interface cannot be opened due to an internal error.
- * - ERROR_INVALID_ARGS The callback handle is invalid (for example, it is null).
* - ERROR_BUSY This interface is in use.
*/
void open(in IThreadChipCallback callback);
@@ -64,11 +60,14 @@
void close();
/**
- * This method resets the Thread HAL internal state. The callback registered by
- * `open()` won’t be reset and the resource allocated by `open()` won’t be free.
+ * This method hardware resets the Thread radio chip via the physical reset pin.
+ * The callback registered by `open()` won’t be reset and the resource allocated
+ * by `open()` won’t be free.
+ *
+ * @throws EX_UNSUPPORTED_OPERATION if the Thread radio chip doesn't support the hardware reset.
*
*/
- void reset();
+ void hardwareReset();
/**
* This method sends a spinel frame to the Thread HAL.
diff --git a/threadnetwork/aidl/default/Android.bp b/threadnetwork/aidl/default/Android.bp
index 8b938d2..bcd5704 100644
--- a/threadnetwork/aidl/default/Android.bp
+++ b/threadnetwork/aidl/default/Android.bp
@@ -79,7 +79,6 @@
"fuzzer.cpp",
],
- required: ["ot-rcp"],
fuzz_config: {
cc: [
"zhanglongxia@google.com",
diff --git a/threadnetwork/aidl/default/fuzzer.cpp b/threadnetwork/aidl/default/fuzzer.cpp
index 512708d..fb6e548 100644
--- a/threadnetwork/aidl/default/fuzzer.cpp
+++ b/threadnetwork/aidl/default/fuzzer.cpp
@@ -22,7 +22,7 @@
using android::fuzzService;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- char url[] = "spinel+hdlc+forkpty:///vendor/bin/ot-rcp?forkpty-arg=2";
+ char url[] = "spinel+hdlc+null:///dev/null";
auto service = ndk::SharedRefBase::make<ThreadChip>(url);
fuzzService(service->asBinder().get(), FuzzedDataProvider(data, size));
diff --git a/threadnetwork/aidl/default/thread_chip.cpp b/threadnetwork/aidl/default/thread_chip.cpp
index 94d1e93..3d38cb8 100644
--- a/threadnetwork/aidl/default/thread_chip.cpp
+++ b/threadnetwork/aidl/default/thread_chip.cpp
@@ -17,6 +17,8 @@
#include "thread_chip.hpp"
#include <android-base/logging.h>
+#include <android/binder_auto_utils.h>
+#include <android/binder_ibinder.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <utils/Log.h>
@@ -46,20 +48,36 @@
mSpinelInterface = std::make_shared<ot::Posix::HdlcInterface>(handleReceivedFrameJump, this,
mRxFrameBuffer);
} else {
- ALOGE("The protocol \"%s\" is not supported!", protocol);
- exit(1);
+ ALOGE("The protocol \"%s\" is not supported", protocol);
+ exit(EXIT_FAILURE);
}
CHECK_NE(mSpinelInterface, nullptr);
+
+ mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
+ AIBinder_DeathRecipient_new(ThreadChip::onBinderDiedJump));
+ AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(), ThreadChip::onBinderUnlinkedJump);
}
-void ThreadChip::clientDeathCallback(void* context) {
- reinterpret_cast<ThreadChip*>(context)->clientDeathCallback();
+ThreadChip::~ThreadChip() {
+ AIBinder_DeathRecipient_delete(mDeathRecipient.get());
}
-void ThreadChip::clientDeathCallback(void) {
- ALOGW("Thread Network HAL client is dead.");
- close();
+void ThreadChip::onBinderDiedJump(void* context) {
+ reinterpret_cast<ThreadChip*>(context)->onBinderDied();
+}
+
+void ThreadChip::onBinderDied(void) {
+ ALOGW("Thread Network HAL client is dead");
+}
+
+void ThreadChip::onBinderUnlinkedJump(void* context) {
+ reinterpret_cast<ThreadChip*>(context)->onBinderUnlinked();
+}
+
+void ThreadChip::onBinderUnlinked(void) {
+ ALOGW("ThreadChip binder is unlinked");
+ deinitChip();
}
void ThreadChip::handleReceivedFrameJump(void* context) {
@@ -76,75 +94,83 @@
}
ndk::ScopedAStatus ThreadChip::open(const std::shared_ptr<IThreadChipCallback>& in_callback) {
- ndk::ScopedAStatus status;
- AIBinder* binder;
+ ndk::ScopedAStatus status = initChip(in_callback);
- VerifyOrExit(mCallback == nullptr,
- status = errorStatus(ERROR_BUSY, "Interface is already opened"));
- VerifyOrExit(in_callback != nullptr,
- status = errorStatus(ERROR_INVALID_ARGS, "The callback is NULL"));
- binder = in_callback->asBinder().get();
- VerifyOrExit(binder != nullptr,
- status = errorStatus(ERROR_FAILED, "Failed to get the callback binder"));
- mBinderDeathRecipient = AIBinder_DeathRecipient_new(clientDeathCallback);
- VerifyOrExit(AIBinder_linkToDeath(binder, mBinderDeathRecipient, this) == STATUS_OK,
- status = errorStatus(ERROR_FAILED, "Failed to link the binder to death"));
- VerifyOrExit(mSpinelInterface->Init(mUrl) == OT_ERROR_NONE,
- status = errorStatus(ERROR_FAILED, "Failed to initialize the interface"));
-
- mCallback = in_callback;
- ot::Posix::Mainloop::Manager::Get().Add(*this);
- status = ndk::ScopedAStatus::ok();
-
-exit:
- if (!status.isOk()) {
- if (mBinderDeathRecipient != nullptr) {
- AIBinder_DeathRecipient_delete(mBinderDeathRecipient);
- mBinderDeathRecipient = nullptr;
- }
- ALOGW("Open failed, error: %s", status.getDescription().c_str());
+ if (status.isOk()) {
+ AIBinder_linkToDeath(in_callback->asBinder().get(), mDeathRecipient.get(), this);
+ ALOGI("Open IThreadChip successfully");
} else {
- ALOGI("open()");
+ ALOGW("Failed to open IThreadChip: %s", status.getDescription().c_str());
}
return status;
}
+ndk::ScopedAStatus ThreadChip::initChip(const std::shared_ptr<IThreadChipCallback>& in_callback) {
+ if (in_callback == nullptr) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ } else if (mCallback == nullptr) {
+ if (mSpinelInterface->Init(mUrl) != OT_ERROR_NONE) {
+ return errorStatus(ERROR_FAILED, "Failed to initialize the interface");
+ }
+
+ mCallback = in_callback;
+ ot::Posix::Mainloop::Manager::Get().Add(*this);
+ return ndk::ScopedAStatus::ok();
+ } else {
+ return errorStatus(ERROR_BUSY, "Interface has been opened");
+ }
+}
+
ndk::ScopedAStatus ThreadChip::close() {
- VerifyOrExit(mCallback != nullptr);
- mCallback = nullptr;
- mSpinelInterface->Deinit();
+ ndk::ScopedAStatus status;
+ std::shared_ptr<IThreadChipCallback> callback = mCallback;
- ot::Posix::Mainloop::Manager::Get().Remove(*this);
+ status = deinitChip();
+ if (status.isOk()) {
+ if (callback != nullptr) {
+ AIBinder_unlinkToDeath(callback->asBinder().get(), mDeathRecipient.get(), this);
+ }
- AIBinder_DeathRecipient_delete(mBinderDeathRecipient);
- mBinderDeathRecipient = nullptr;
+ ALOGI("Close IThreadChip successfully");
+ } else {
+ ALOGW("Failed to close IThreadChip: %s", status.getDescription().c_str());
+ }
-exit:
- ALOGI("close()");
- return ndk::ScopedAStatus::ok();
+ return status;
+}
+
+ndk::ScopedAStatus ThreadChip::deinitChip() {
+ if (mCallback != nullptr) {
+ mSpinelInterface->Deinit();
+ ot::Posix::Mainloop::Manager::Get().Remove(*this);
+ mCallback = nullptr;
+ return ndk::ScopedAStatus::ok();
+ }
+
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
}
ndk::ScopedAStatus ThreadChip::sendSpinelFrame(const std::vector<uint8_t>& in_frame) {
ndk::ScopedAStatus status;
otError error;
- VerifyOrExit(mCallback != nullptr,
- status = errorStatus(ERROR_FAILED, "The interface is not open"));
-
- error = mSpinelInterface->SendFrame(reinterpret_cast<const uint8_t*>(in_frame.data()),
- in_frame.size());
- if (error == OT_ERROR_NONE) {
- status = ndk::ScopedAStatus::ok();
- } else if (error == OT_ERROR_NO_BUFS) {
- status = errorStatus(ERROR_NO_BUFS, "Insufficient buffer space to send");
- } else if (error == OT_ERROR_BUSY) {
- status = errorStatus(ERROR_BUSY, "The interface is busy");
+ if (mCallback == nullptr) {
+ status = errorStatus(ERROR_FAILED, "The interface is not open");
} else {
- status = errorStatus(ERROR_FAILED, "Failed to send the spinel frame");
+ error = mSpinelInterface->SendFrame(reinterpret_cast<const uint8_t*>(in_frame.data()),
+ in_frame.size());
+ if (error == OT_ERROR_NONE) {
+ status = ndk::ScopedAStatus::ok();
+ } else if (error == OT_ERROR_NO_BUFS) {
+ status = errorStatus(ERROR_NO_BUFS, "Insufficient buffer space to send");
+ } else if (error == OT_ERROR_BUSY) {
+ status = errorStatus(ERROR_BUSY, "The interface is busy");
+ } else {
+ status = errorStatus(ERROR_FAILED, "Failed to send the spinel frame");
+ }
}
-exit:
if (!status.isOk()) {
ALOGW("Send spinel frame failed, error: %s", status.getDescription().c_str());
}
@@ -152,8 +178,11 @@
return status;
}
-ndk::ScopedAStatus ThreadChip::reset() {
- mSpinelInterface->HardwareReset();
+ndk::ScopedAStatus ThreadChip::hardwareReset() {
+ if (mSpinelInterface->HardwareReset() == OT_ERROR_NOT_IMPLEMENTED) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ }
+
ALOGI("reset()");
return ndk::ScopedAStatus::ok();
}
diff --git a/threadnetwork/aidl/default/thread_chip.hpp b/threadnetwork/aidl/default/thread_chip.hpp
index 294190a..1ab6d54 100644
--- a/threadnetwork/aidl/default/thread_chip.hpp
+++ b/threadnetwork/aidl/default/thread_chip.hpp
@@ -22,6 +22,7 @@
#include "lib/spinel/spinel_interface.hpp"
#include "mainloop.hpp"
+#include <android/binder_auto_utils.h>
#include <android/binder_ibinder.h>
#include <utils/Mutex.h>
@@ -33,26 +34,31 @@
class ThreadChip : public BnThreadChip, ot::Posix::Mainloop::Source {
public:
ThreadChip(char* url);
+ ~ThreadChip();
ndk::ScopedAStatus open(const std::shared_ptr<IThreadChipCallback>& in_callback) override;
ndk::ScopedAStatus close() override;
ndk::ScopedAStatus sendSpinelFrame(const std::vector<uint8_t>& in_frame) override;
- ndk::ScopedAStatus reset() override;
+ ndk::ScopedAStatus hardwareReset() override;
void Update(otSysMainloopContext& context) override;
void Process(const otSysMainloopContext& context) override;
private:
- static void clientDeathCallback(void* context);
- void clientDeathCallback(void);
+ static void onBinderDiedJump(void* context);
+ void onBinderDied(void);
+ static void onBinderUnlinkedJump(void* context);
+ void onBinderUnlinked(void);
static void handleReceivedFrameJump(void* context);
void handleReceivedFrame(void);
ndk::ScopedAStatus errorStatus(int32_t error, const char* message);
+ ndk::ScopedAStatus initChip(const std::shared_ptr<IThreadChipCallback>& in_callback);
+ ndk::ScopedAStatus deinitChip();
ot::Url::Url mUrl;
std::shared_ptr<ot::Spinel::SpinelInterface> mSpinelInterface;
ot::Spinel::SpinelInterface::RxFrameBuffer mRxFrameBuffer;
std::shared_ptr<IThreadChipCallback> mCallback;
- AIBinder_DeathRecipient* mBinderDeathRecipient;
+ ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
};
} // namespace threadnetwork
diff --git a/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp b/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
index 04c6dea..5925b54 100644
--- a/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
+++ b/threadnetwork/aidl/vts/VtsHalThreadNetworkTargetTest.cpp
@@ -91,7 +91,7 @@
ndk::SharedRefBase::make<ThreadChipCallback>([](auto /* data */) {});
EXPECT_TRUE(thread_chip->open(callback).isOk());
- EXPECT_TRUE(thread_chip->reset().isOk());
+ EXPECT_TRUE(thread_chip->hardwareReset().isOk());
}
TEST_P(ThreadNetworkAidl, SendSpinelFrame) {
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorDataPacketFormat.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorDataPacketFormat.aidl
new file mode 100644
index 0000000..efafa32
--- /dev/null
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorDataPacketFormat.aidl
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.uwb.fira_android;
+@Backing(type="byte") @VintfStability
+enum UwbVendorDataPacketFormat {
+ RADAR_DATA_MESSAGE = 0xF,
+}
diff --git a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
index 34bc4ec..1506406 100644
--- a/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
+++ b/uwb/aidl/aidl_api/android.hardware.uwb.fira_android/current/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
@@ -39,5 +39,4 @@
ANDROID_RANGE_DIAGNOSTICS = 0x2,
RADAR_SET_APP_CONFIG = 0x11,
RADAR_GET_APP_CONFIG = 0x12,
- RADAR_DATA_NTF = 0x13,
}
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorDataPacketFormat.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorDataPacketFormat.aidl
new file mode 100644
index 0000000..7a1b033
--- /dev/null
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorDataPacketFormat.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package android.hardware.uwb.fira_android;
+
+/**
+ * Android specific vendor DPF (Data Packet Format) should be defined here.
+ */
+@VintfStability
+@Backing(type="byte")
+enum UwbVendorDataPacketFormat {
+ // Used to send radar data messages from UWBS to the host.
+ RADAR_DATA_MESSAGE = 0xF,
+}
diff --git a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
index 203b940..95c10a8 100644
--- a/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
+++ b/uwb/aidl/android/hardware/uwb/fira_android/UwbVendorGidAndroidOids.aidl
@@ -46,6 +46,4 @@
RADAR_SET_APP_CONFIG = 0x11,
// Used to get application configurations for radar session.
RADAR_GET_APP_CONFIG = 0x12,
- // Used to report radar data for certain radar data types.
- RADAR_DATA_NTF = 0x13,
}
diff --git a/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp
index bebad7c..738e72c 100644
--- a/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp
+++ b/wifi/aidl/vts/functional/wifi_nan_iface_aidl_test.cpp
@@ -76,18 +76,10 @@
void TearDown() override { stopWifiService(getInstanceName()); }
- // Used as a mechanism to inform the test about data/event callbacks.
- inline void notify() {
- std::unique_lock<std::mutex> lock(mtx_);
- count_++;
- cv_.notify_one();
- }
-
enum CallbackType {
- INVALID = -2,
- ANY_CALLBACK = -1,
+ INVALID = 0,
- NOTIFY_CAPABILITIES_RESPONSE = 0,
+ NOTIFY_CAPABILITIES_RESPONSE = 1,
NOTIFY_ENABLE_RESPONSE,
NOTIFY_CONFIG_RESPONSE,
NOTIFY_DISABLE_RESPONSE,
@@ -128,310 +120,278 @@
EVENT_SUSPENSION_MODE_CHANGE,
};
+ // Used as a mechanism to inform the test about data/event callbacks.
+ inline void notify(CallbackType callbackType) {
+ std::unique_lock<std::mutex> lock(mtx_);
+ callback_event_bitmap_ |= (UINT64_C(0x1) << callbackType);
+ cv_.notify_one();
+ }
+
// Test code calls this function to wait for data/event callback.
- // Must set callbackType = INVALID before calling this function.
+ // Must set callback_event_bitmap_ to 0 before calling this function.
inline std::cv_status wait(CallbackType waitForCallbackType) {
std::unique_lock<std::mutex> lock(mtx_);
EXPECT_NE(INVALID, waitForCallbackType);
std::cv_status status = std::cv_status::no_timeout;
auto now = std::chrono::system_clock::now();
- while (count_ == 0) {
+ while (!(receivedCallback(waitForCallbackType))) {
status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
if (status == std::cv_status::timeout) return status;
- if (waitForCallbackType != ANY_CALLBACK && callback_type_ != INVALID &&
- callback_type_ != waitForCallbackType) {
- count_--;
- }
}
- count_--;
return status;
}
+ inline bool receivedCallback(CallbackType waitForCallbackType) {
+ return callback_event_bitmap_ & (UINT64_C(0x1) << waitForCallbackType);
+ }
+
class WifiNanIfaceEventCallback : public BnWifiNanIfaceEventCallback {
public:
WifiNanIfaceEventCallback(WifiNanIfaceAidlTest& parent) : parent_(parent){};
::ndk::ScopedAStatus eventClusterEvent(const NanClusterEventInd& event) override {
- parent_.callback_type_ = EVENT_CLUSTER_EVENT;
parent_.nan_cluster_event_ind_ = event;
- parent_.notify();
+ parent_.notify(EVENT_CLUSTER_EVENT);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventDataPathConfirm(const NanDataPathConfirmInd& event) override {
- parent_.callback_type_ = EVENT_DATA_PATH_CONFIRM;
parent_.nan_data_path_confirm_ind_ = event;
- parent_.notify();
+ parent_.notify(EVENT_DATA_PATH_CONFIRM);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventDataPathRequest(const NanDataPathRequestInd& event) override {
- parent_.callback_type_ = EVENT_DATA_PATH_REQUEST;
parent_.nan_data_path_request_ind_ = event;
- parent_.notify();
+ parent_.notify(EVENT_DATA_PATH_REQUEST);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventDataPathScheduleUpdate(
const NanDataPathScheduleUpdateInd& event) override {
- parent_.callback_type_ = EVENT_DATA_PATH_SCHEDULE_UPDATE;
parent_.nan_data_path_schedule_update_ind_ = event;
- parent_.notify();
+ parent_.notify(EVENT_DATA_PATH_SCHEDULE_UPDATE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventDataPathTerminated(int32_t ndpInstanceId) override {
- parent_.callback_type_ = EVENT_DATA_PATH_TERMINATED;
parent_.ndp_instance_id_ = ndpInstanceId;
- parent_.notify();
+ parent_.notify(EVENT_DATA_PATH_TERMINATED);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventDisabled(const NanStatus& status) override {
- parent_.callback_type_ = EVENT_DISABLED;
parent_.status_ = status;
- parent_.notify();
+ parent_.notify(EVENT_DISABLED);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventFollowupReceived(const NanFollowupReceivedInd& event) override {
- parent_.callback_type_ = EVENT_FOLLOWUP_RECEIVED;
parent_.nan_followup_received_ind_ = event;
- parent_.notify();
+ parent_.notify(EVENT_FOLLOWUP_RECEIVED);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventMatch(const NanMatchInd& event) override {
- parent_.callback_type_ = EVENT_MATCH;
parent_.nan_match_ind_ = event;
- parent_.notify();
+ parent_.notify(EVENT_MATCH);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventMatchExpired(int8_t discoverySessionId, int32_t peerId) override {
- parent_.callback_type_ = EVENT_MATCH_EXPIRED;
parent_.session_id_ = discoverySessionId;
parent_.peer_id_ = peerId;
- parent_.notify();
+ parent_.notify(EVENT_MATCH_EXPIRED);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventPublishTerminated(int8_t sessionId,
const NanStatus& status) override {
- parent_.callback_type_ = EVENT_PUBLISH_TERMINATED;
parent_.session_id_ = sessionId;
parent_.status_ = status;
- parent_.notify();
+ parent_.notify(EVENT_PUBLISH_TERMINATED);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventSubscribeTerminated(int8_t sessionId,
const NanStatus& status) override {
- parent_.callback_type_ = EVENT_SUBSCRIBE_TERMINATED;
parent_.session_id_ = sessionId;
parent_.status_ = status;
- parent_.notify();
+ parent_.notify(EVENT_SUBSCRIBE_TERMINATED);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventTransmitFollowup(char16_t id, const NanStatus& status) override {
- parent_.callback_type_ = EVENT_TRANSMIT_FOLLOWUP;
parent_.id_ = id;
parent_.status_ = status;
- parent_.notify();
+ parent_.notify(EVENT_TRANSMIT_FOLLOWUP);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventPairingConfirm(const NanPairingConfirmInd& event) override {
- parent_.callback_type_ = EVENT_PAIRING_CONFIRM;
parent_.nan_pairing_confirm_ind_ = event;
- parent_.notify();
+ parent_.notify(EVENT_PAIRING_CONFIRM);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventPairingRequest(const NanPairingRequestInd& event) override {
- parent_.callback_type_ = EVENT_PAIRING_REQUEST;
parent_.nan_pairing_request_ind_ = event;
- parent_.notify();
+ parent_.notify(EVENT_PAIRING_REQUEST);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventBootstrappingConfirm(
const NanBootstrappingConfirmInd& event) override {
- parent_.callback_type_ = EVENT_BOOTSTRAPPING_CONFIRM;
parent_.nan_bootstrapping_confirm_ind_ = event;
- parent_.notify();
+ parent_.notify(EVENT_BOOTSTRAPPING_CONFIRM);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventBootstrappingRequest(
const NanBootstrappingRequestInd& event) override {
- parent_.callback_type_ = EVENT_BOOTSTRAPPING_REQUEST;
parent_.nan_bootstrapping_request_ind_ = event;
- parent_.notify();
+ parent_.notify(EVENT_BOOTSTRAPPING_REQUEST);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus eventSuspensionModeChanged(
const NanSuspensionModeChangeInd& event) override {
- parent_.callback_type_ = EVENT_SUSPENSION_MODE_CHANGE;
parent_.nan_suspension_mode_change_ind_ = event;
- parent_.notify();
+ parent_.notify(EVENT_SUSPENSION_MODE_CHANGE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyCapabilitiesResponse(
char16_t id, const NanStatus& status,
const NanCapabilities& capabilities) override {
- parent_.callback_type_ = NOTIFY_CAPABILITIES_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
parent_.capabilities_ = capabilities;
- parent_.notify();
+ parent_.notify(NOTIFY_CAPABILITIES_RESPONSE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyConfigResponse(char16_t id, const NanStatus& status) override {
- parent_.callback_type_ = NOTIFY_CONFIG_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
- parent_.notify();
+ parent_.notify(NOTIFY_CONFIG_RESPONSE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyCreateDataInterfaceResponse(char16_t id,
const NanStatus& status) override {
- parent_.callback_type_ = NOTIFY_CREATE_DATA_INTERFACE_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
- parent_.notify();
+ parent_.notify(NOTIFY_CREATE_DATA_INTERFACE_RESPONSE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyDeleteDataInterfaceResponse(char16_t id,
const NanStatus& status) override {
- parent_.callback_type_ = NOTIFY_DELETE_DATA_INTERFACE_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
- parent_.notify();
+ parent_.notify(NOTIFY_DELETE_DATA_INTERFACE_RESPONSE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyDisableResponse(char16_t id, const NanStatus& status) override {
- parent_.callback_type_ = NOTIFY_DISABLE_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
- parent_.notify();
+ parent_.notify(NOTIFY_DISABLE_RESPONSE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyEnableResponse(char16_t id, const NanStatus& status) override {
- parent_.callback_type_ = NOTIFY_ENABLE_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
- parent_.notify();
+ parent_.notify(NOTIFY_ENABLE_RESPONSE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyInitiateDataPathResponse(char16_t id, const NanStatus& status,
int32_t ndpInstanceId) override {
- parent_.callback_type_ = NOTIFY_INITIATE_DATA_PATH_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
parent_.ndp_instance_id_ = ndpInstanceId;
- parent_.notify();
+ parent_.notify(NOTIFY_INITIATE_DATA_PATH_RESPONSE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyRespondToDataPathIndicationResponse(
char16_t id, const NanStatus& status) override {
- parent_.callback_type_ = NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
- parent_.notify();
+ parent_.notify(NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyStartPublishResponse(char16_t id, const NanStatus& status,
int8_t sessionId) override {
- parent_.callback_type_ = NOTIFY_START_PUBLISH_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
parent_.session_id_ = sessionId;
- parent_.notify();
+ parent_.notify(NOTIFY_START_PUBLISH_RESPONSE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyStartSubscribeResponse(char16_t id, const NanStatus& status,
int8_t sessionId) override {
- parent_.callback_type_ = NOTIFY_START_SUBSCRIBE_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
parent_.session_id_ = sessionId;
- parent_.notify();
+ parent_.notify(NOTIFY_START_SUBSCRIBE_RESPONSE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyStopPublishResponse(char16_t id,
const NanStatus& status) override {
- parent_.callback_type_ = NOTIFY_STOP_PUBLISH_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
- parent_.notify();
+ parent_.notify(NOTIFY_STOP_PUBLISH_RESPONSE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyStopSubscribeResponse(char16_t id,
const NanStatus& status) override {
- parent_.callback_type_ = NOTIFY_STOP_SUBSCRIBE_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
- parent_.notify();
+ parent_.notify(NOTIFY_STOP_SUBSCRIBE_RESPONSE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyTerminateDataPathResponse(char16_t id,
const NanStatus& status) override {
- parent_.callback_type_ = NOTIFY_TERMINATE_DATA_PATH_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
- parent_.notify();
+ parent_.notify(NOTIFY_TERMINATE_DATA_PATH_RESPONSE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifySuspendResponse(char16_t id, const NanStatus& status) override {
- parent_.callback_type_ = NOTIFY_SUSPEND_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
- parent_.notify();
+ parent_.notify(NOTIFY_SUSPEND_RESPONSE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyResumeResponse(char16_t id, const NanStatus& status) override {
- parent_.callback_type_ = NOTIFY_RESUME_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
- parent_.notify();
+ parent_.notify(NOTIFY_RESUME_RESPONSE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyTransmitFollowupResponse(char16_t id,
const NanStatus& status) override {
- parent_.callback_type_ = NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
- parent_.notify();
+ parent_.notify(NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyInitiatePairingResponse(char16_t id, const NanStatus& status,
int32_t pairingInstanceId) override {
- parent_.callback_type_ = NOTIFY_INITIATE_PAIRING_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
parent_.pairing_instance_id_ = pairingInstanceId;
- parent_.notify();
+ parent_.notify(NOTIFY_INITIATE_PAIRING_RESPONSE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyRespondToPairingIndicationResponse(
char16_t id, const NanStatus& status) override {
- parent_.callback_type_ = NOTIFY_RESPOND_TO_PAIRING_INDICATION_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
- parent_.notify();
+ parent_.notify(NOTIFY_RESPOND_TO_PAIRING_INDICATION_RESPONSE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyInitiateBootstrappingResponse(
char16_t id, const NanStatus& status, int32_t bootstrapppingInstanceId) override {
- parent_.callback_type_ = NOTIFY_INITIATE_BOOTSTRAPPING_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
parent_.bootstrappping_instance_id_ = bootstrapppingInstanceId;
- parent_.notify();
+ parent_.notify(NOTIFY_INITIATE_BOOTSTRAPPING_RESPONSE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyRespondToBootstrappingIndicationResponse(
char16_t id, const NanStatus& status) override {
- parent_.callback_type_ = NOTIFY_RESPOND_TO_BOOTSTRAPPING_INDICATION_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
- parent_.notify();
+ parent_.notify(NOTIFY_RESPOND_TO_BOOTSTRAPPING_INDICATION_RESPONSE);
return ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus notifyTerminatePairingResponse(char16_t id,
const NanStatus& status) override {
- parent_.callback_type_ = NOTIFY_TERMINATE_PAIRING_RESPONSE;
parent_.id_ = id;
parent_.status_ = status;
- parent_.notify();
+ parent_.notify(NOTIFY_TERMINATE_PAIRING_RESPONSE);
return ndk::ScopedAStatus::ok();
}
@@ -441,7 +401,7 @@
protected:
std::shared_ptr<IWifiNanIface> wifi_nan_iface_;
- CallbackType callback_type_;
+ uint64_t callback_event_bitmap_;
uint16_t id_;
uint8_t session_id_;
uint32_t ndp_instance_id_;
@@ -468,7 +428,6 @@
// synchronization objects
std::mutex mtx_;
std::condition_variable cv_;
- int count_ = 0;
};
/*
@@ -488,7 +447,7 @@
*/
TEST_P(WifiNanIfaceAidlTest, EnableRequest_InvalidArgs) {
uint16_t inputCmdId = 10;
- callback_type_ = INVALID;
+ callback_event_bitmap_ = 0;
NanEnableRequest nanEnableRequest = {};
NanConfigRequestSupplemental nanConfigRequestSupp = {};
auto status =
@@ -498,7 +457,7 @@
// Wait for a callback.
ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE));
- ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callback_type_);
+ ASSERT_TRUE(receivedCallback(NOTIFY_ENABLE_RESPONSE));
ASSERT_EQ(id_, inputCmdId);
ASSERT_EQ(status_.status, NanStatusCode::INVALID_ARGS);
}
@@ -509,7 +468,7 @@
*/
TEST_P(WifiNanIfaceAidlTest, ConfigRequest_InvalidArgs) {
uint16_t inputCmdId = 10;
- callback_type_ = INVALID;
+ callback_event_bitmap_ = 0;
NanConfigRequest nanConfigRequest = {};
NanConfigRequestSupplemental nanConfigRequestSupp = {};
auto status =
@@ -520,7 +479,7 @@
// Wait for a callback.
ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CONFIG_RESPONSE));
- ASSERT_EQ(NOTIFY_CONFIG_RESPONSE, callback_type_);
+ ASSERT_TRUE(receivedCallback(NOTIFY_CONFIG_RESPONSE));
ASSERT_EQ(id_, inputCmdId);
ASSERT_EQ(status_.status, NanStatusCode::INVALID_ARGS);
}
@@ -561,12 +520,12 @@
*/
TEST_P(WifiNanIfaceAidlTest, NotifyCapabilitiesResponse) {
uint16_t inputCmdId = 10;
- callback_type_ = INVALID;
+ callback_event_bitmap_ = 0;
EXPECT_TRUE(wifi_nan_iface_->getCapabilitiesRequest(inputCmdId).isOk());
// Wait for a callback.
ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CAPABILITIES_RESPONSE));
- ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE, callback_type_);
+ ASSERT_TRUE(receivedCallback(NOTIFY_CAPABILITIES_RESPONSE));
ASSERT_EQ(id_, inputCmdId);
ASSERT_EQ(status_.status, NanStatusCode::SUCCESS);
@@ -654,14 +613,14 @@
nanConfigRequestSupp.numberOfSpatialStreamsInDiscovery = 0;
nanConfigRequestSupp.enableDiscoveryWindowEarlyTermination = false;
- callback_type_ = INVALID;
+ callback_event_bitmap_ = 0;
auto status = wifi_nan_iface_->enableRequest(inputCmdId, req, nanConfigRequestSupp);
if (!checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
ASSERT_TRUE(status.isOk());
// Wait for a callback.
ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_ENABLE_RESPONSE));
- ASSERT_EQ(NOTIFY_ENABLE_RESPONSE, callback_type_);
+ ASSERT_TRUE(receivedCallback(NOTIFY_ENABLE_RESPONSE));
ASSERT_EQ(id_, inputCmdId);
ASSERT_EQ(status_.status, NanStatusCode::SUCCESS);
}
@@ -688,7 +647,7 @@
// Wait for a callback.
ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_START_PUBLISH_RESPONSE));
- ASSERT_EQ(NOTIFY_START_PUBLISH_RESPONSE, callback_type_);
+ ASSERT_TRUE(receivedCallback(NOTIFY_START_PUBLISH_RESPONSE));
ASSERT_EQ(id_, inputCmdId + 1);
ASSERT_EQ(status_.status, NanStatusCode::SUCCESS);
}
@@ -699,7 +658,7 @@
*/
TEST_P(WifiNanIfaceAidlTest, RespondToDataPathIndicationRequest_InvalidArgs) {
uint16_t inputCmdId = 10;
- callback_type_ = INVALID;
+ callback_event_bitmap_ = 0;
NanRespondToDataPathIndicationRequest nanRespondToDataPathIndicationRequest = {};
nanRespondToDataPathIndicationRequest.ifaceName = "AwareInterfaceNameTooLong";
auto status = wifi_nan_iface_->respondToDataPathIndicationRequest(
@@ -716,7 +675,7 @@
*/
TEST_P(WifiNanIfaceAidlTest, InitiateDataPathRequest_InvalidArgs) {
uint16_t inputCmdId = 10;
- callback_type_ = INVALID;
+ callback_event_bitmap_ = 0;
NanInitiateDataPathRequest nanInitiateDataPathRequest = {};
nanInitiateDataPathRequest.ifaceName = "AwareInterfaceNameTooLong";
auto status = wifi_nan_iface_->initiateDataPathRequest(inputCmdId, nanInitiateDataPathRequest);