diff options
70 files changed, 3517 insertions, 725 deletions
diff --git a/atrace/1.0/default/android.hardware.atrace@1.0-service.rc b/atrace/1.0/default/android.hardware.atrace@1.0-service.rc index 7110b45c9f..31459b4916 100644 --- a/atrace/1.0/default/android.hardware.atrace@1.0-service.rc +++ b/atrace/1.0/default/android.hardware.atrace@1.0-service.rc @@ -14,4 +14,4 @@ service vendor.atrace-hal-1-0 /vendor/bin/hw/android.hardware.atrace@1.0-service interface android.hardware.atrace@1.0::IAtraceDevice default class early_hal user system - group system + group system readtracefs diff --git a/audio/core/all-versions/default/Android.bp b/audio/core/all-versions/default/Android.bp index 901b7eeab9..b170ff4d42 100644 --- a/audio/core/all-versions/default/Android.bp +++ b/audio/core/all-versions/default/Android.bp @@ -48,6 +48,8 @@ cc_defaults { "libhidlbase", "liblog", "libmedia_helper", + "libmediautils_vendor", + "libmemunreachable", "libutils", "android.hardware.audio.common-util", ], @@ -138,8 +140,8 @@ cc_library_shared { defaults: ["android.hardware.audio@6.0-impl_default"], } -cc_library_shared { - name: "android.hardware.audio@7.0-impl", +cc_defaults { + name: "android.hardware.audio@7.0-impl_default", defaults: ["android.hardware.audio-impl_default"], shared_libs: [ "android.hardware.audio@7.0", @@ -155,3 +157,8 @@ cc_library_shared { "-include common/all-versions/VersionMacro.h", ], } + +cc_library_shared { + name: "android.hardware.audio@7.0-impl", + defaults: ["android.hardware.audio@7.0-impl_default"], +} diff --git a/audio/core/all-versions/default/Device.cpp b/audio/core/all-versions/default/Device.cpp index 130dfba95b..c33e6f30fa 100644 --- a/audio/core/all-versions/default/Device.cpp +++ b/audio/core/all-versions/default/Device.cpp @@ -30,6 +30,8 @@ #include <algorithm> #include <android/log.h> +#include <mediautils/MemoryLeakTrackUtil.h> +#include <memunreachable/memunreachable.h> #include <HidlUtils.h> @@ -456,9 +458,32 @@ Return<void> Device::debugDump(const hidl_handle& fd) { } #endif -Return<void> Device::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& /* options */) { +Return<void> Device::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) { if (fd.getNativeHandle() != nullptr && fd->numFds == 1) { - analyzeStatus("dump", mDevice->dump(mDevice, fd->data[0])); + const int fd0 = fd->data[0]; + bool dumpMem = false; + bool unreachableMemory = false; + for (const auto& option : options) { + if (option == "-m") { + dumpMem = true; + } else if (option == "--unreachable") { + unreachableMemory = true; + } + } + + if (dumpMem) { + dprintf(fd0, "\nDumping memory:\n"); + std::string s = dumpMemoryAddresses(100 /* limit */); + write(fd0, s.c_str(), s.size()); + } + if (unreachableMemory) { + dprintf(fd0, "\nDumping unreachable memory:\n"); + // TODO - should limit be an argument parameter? + std::string s = GetUnreachableMemoryString(true /* contents */, 100 /* limit */); + write(fd0, s.c_str(), s.size()); + } + + analyzeStatus("dump", mDevice->dump(mDevice, fd0)); } return Void(); } diff --git a/audio/core/all-versions/vts/functional/6.0/Generators.cpp b/audio/core/all-versions/vts/functional/6.0/Generators.cpp index 6b4dbc17af..e3b98c909f 100644 --- a/audio/core/all-versions/vts/functional/6.0/Generators.cpp +++ b/audio/core/all-versions/vts/functional/6.0/Generators.cpp @@ -36,9 +36,14 @@ using namespace ::android::hardware::audio::CPP_VERSION; std::vector<DeviceConfigParameter> generateOutputDeviceConfigParameters(bool oneProfilePerDevice) { std::vector<DeviceConfigParameter> result; for (const auto& device : getDeviceParameters()) { - auto module = - getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device)); + const std::string moduleName = std::get<PARAM_DEVICE_NAME>(device); + auto module = getCachedPolicyConfig().getModuleFromName(moduleName); for (const auto& ioProfile : module->getOutputProfiles()) { + if (getCachedPolicyConfig() + .getAttachedSinkDeviceForMixPort(moduleName, ioProfile->getName()) + .empty()) { + continue; // no attached device + } for (const auto& profile : ioProfile->getAudioProfiles()) { const auto& channels = profile->getChannels(); const auto& sampleRates = profile->getSampleRates(); @@ -94,9 +99,14 @@ const std::vector<DeviceConfigParameter>& getOutputDeviceSingleConfigParameters( std::vector<DeviceConfigParameter> generateInputDeviceConfigParameters(bool oneProfilePerDevice) { std::vector<DeviceConfigParameter> result; for (const auto& device : getDeviceParameters()) { - auto module = - getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device)); + const std::string moduleName = std::get<PARAM_DEVICE_NAME>(device); + auto module = getCachedPolicyConfig().getModuleFromName(moduleName); for (const auto& ioProfile : module->getInputProfiles()) { + if (getCachedPolicyConfig() + .getAttachedSourceDeviceForMixPort(moduleName, ioProfile->getName()) + .empty()) { + continue; // no attached device + } for (const auto& profile : ioProfile->getAudioProfiles()) { const auto& channels = profile->getChannels(); const auto& sampleRates = profile->getSampleRates(); diff --git a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp index 0cc6a5b964..27598012fe 100644 --- a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp +++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp @@ -499,18 +499,10 @@ static const std::vector<DeviceConfigParameter>& getOutputDevicePcmOnlyConfigPar return xsd::isLinearPcm(std::get<PARAM_CONFIG>(cfg).base.format) // MMAP NOIRQ and HW A/V Sync profiles use special writing protocols. && - std::find_if(flags.begin(), flags.end(), - [](const auto& flag) { - return flag == toString(xsd::AudioInOutFlag:: - AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) || - flag == toString(xsd::AudioInOutFlag:: - AUDIO_OUTPUT_FLAG_HW_AV_SYNC); - }) == flags.end() && - !getCachedPolicyConfig() - .getAttachedSinkDeviceForMixPort( - std::get<PARAM_DEVICE_NAME>(std::get<PARAM_DEVICE>(cfg)), - std::get<PARAM_PORT_NAME>(cfg)) - .empty(); + std::find_if(flags.begin(), flags.end(), [](const auto& flag) { + return flag == toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) || + flag == toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_HW_AV_SYNC); + }) == flags.end(); }); return pcmParams; }(); @@ -677,20 +669,13 @@ static const std::vector<DeviceConfigParameter>& getInputDevicePcmOnlyConfigPara // reading h/w hotword might require Soundtrigger to be active. && std::find_if( - flags.begin(), flags.end(), - [](const auto& flag) { + flags.begin(), flags.end(), [](const auto& flag) { return flag == toString( xsd::AudioInOutFlag:: AUDIO_INPUT_FLAG_MMAP_NOIRQ) || flag == toString(xsd::AudioInOutFlag:: AUDIO_INPUT_FLAG_HW_HOTWORD); - }) == flags.end() && - !getCachedPolicyConfig() - .getAttachedSourceDeviceForMixPort( - std::get<PARAM_DEVICE_NAME>( - std::get<PARAM_DEVICE>(cfg)), - std::get<PARAM_PORT_NAME>(cfg)) - .empty(); + }) == flags.end(); }); return pcmParams; }(); diff --git a/audio/core/all-versions/vts/functional/7.0/Generators.cpp b/audio/core/all-versions/vts/functional/7.0/Generators.cpp index d2ba3397af..42bf1d341d 100644 --- a/audio/core/all-versions/vts/functional/7.0/Generators.cpp +++ b/audio/core/all-versions/vts/functional/7.0/Generators.cpp @@ -95,13 +95,21 @@ static AudioOffloadInfo generateOffloadInfo(const AudioConfigBase& base) { std::vector<DeviceConfigParameter> generateOutputDeviceConfigParameters(bool oneProfilePerDevice) { std::vector<DeviceConfigParameter> result; for (const auto& device : getDeviceParameters()) { - auto module = - getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device)); + const std::string moduleName = std::get<PARAM_DEVICE_NAME>(device); + auto module = getCachedPolicyConfig().getModuleFromName(moduleName); if (!module || !module->getFirstMixPorts()) break; for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) { if (mixPort.getRole() != xsd::Role::source) continue; // not an output profile + if (getCachedPolicyConfig() + .getAttachedSinkDeviceForMixPort(moduleName, mixPort.getName()) + .empty()) { + continue; // no attached device + } auto [flags, isOffload] = generateOutFlags(mixPort); for (const auto& profile : mixPort.getProfile()) { + if (!profile.hasFormat() || !profile.hasSamplingRates() || + !profile.hasChannelMasks()) + continue; auto configs = combineAudioConfig(profile.getChannelMasks(), profile.getSamplingRates(), profile.getFormat()); for (auto& config : configs) { @@ -220,17 +228,25 @@ const std::vector<DeviceConfigParameter>& getOutputDeviceInvalidConfigParameters std::vector<DeviceConfigParameter> generateInputDeviceConfigParameters(bool oneProfilePerDevice) { std::vector<DeviceConfigParameter> result; for (const auto& device : getDeviceParameters()) { - auto module = - getCachedPolicyConfig().getModuleFromName(std::get<PARAM_DEVICE_NAME>(device)); + const std::string moduleName = std::get<PARAM_DEVICE_NAME>(device); + auto module = getCachedPolicyConfig().getModuleFromName(moduleName); if (!module || !module->getFirstMixPorts()) break; for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) { if (mixPort.getRole() != xsd::Role::sink) continue; // not an input profile + if (getCachedPolicyConfig() + .getAttachedSourceDeviceForMixPort(moduleName, mixPort.getName()) + .empty()) { + continue; // no attached device + } std::vector<AudioInOutFlag> flags; if (mixPort.hasFlags()) { std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(), std::back_inserter(flags), [](auto flag) { return toString(flag); }); } for (const auto& profile : mixPort.getProfile()) { + if (!profile.hasFormat() || !profile.hasSamplingRates() || + !profile.hasChannelMasks()) + continue; auto configs = combineAudioConfig(profile.getChannelMasks(), profile.getSamplingRates(), profile.getFormat()); for (const auto& config : configs) { diff --git a/audio/core/all-versions/vts/functional/Android.bp b/audio/core/all-versions/vts/functional/Android.bp index e446a7f2cf..cfee26ada5 100644 --- a/audio/core/all-versions/vts/functional/Android.bp +++ b/audio/core/all-versions/vts/functional/Android.bp @@ -211,6 +211,7 @@ cc_test { data: [ "tests/apm_config_no_vx.xml", "tests/apm_config_with_vx.xml", + "tests/apm_config_b_205808571_6_0.xml", ], test_config: "tests/HalAudioV6_0GeneratorTest.xml", } @@ -239,6 +240,8 @@ cc_test { data: [ "tests/apm_config_no_vx_7_0.xml", "tests/apm_config_with_vx_7_0.xml", + "tests/apm_config_b_204314749_7_0.xml", + "tests/apm_config_b_205808571_7_0.xml", ], test_config: "tests/HalAudioV7_0GeneratorTest.xml", } diff --git a/audio/core/all-versions/vts/functional/PolicyConfig.h b/audio/core/all-versions/vts/functional/PolicyConfig.h index a94041c427..171d03f42a 100644 --- a/audio/core/all-versions/vts/functional/PolicyConfig.h +++ b/audio/core/all-versions/vts/functional/PolicyConfig.h @@ -76,6 +76,16 @@ class PolicyConfig : private PolicyConfigData, public android::AudioPolicyConfig const std::set<std::string>& getModulesWithDevicesNames() const { return mModulesWithDevicesNames; } + std::string getAttachedSinkDeviceForMixPort(const std::string& moduleName, + const std::string& mixPortName) const { + return findAttachedDevice(getAttachedDevices(moduleName), + getSinkDevicesForMixPort(moduleName, mixPortName)); + } + std::string getAttachedSourceDeviceForMixPort(const std::string& moduleName, + const std::string& mixPortName) const { + return findAttachedDevice(getAttachedDevices(moduleName), + getSourceDevicesForMixPort(moduleName, mixPortName)); + } bool haveInputProfilesInModule(const std::string& name) const { auto module = getModuleFromName(name); return module && !module->getInputProfiles().empty(); @@ -92,6 +102,8 @@ class PolicyConfig : private PolicyConfigData, public android::AudioPolicyConfig for (const auto& module : hwModules) { if (module->getDeclaredDevices().indexOf(device) >= 0) { mModulesWithDevicesNames.insert(module->getName()); + mAttachedDevicesPerModule[module->getName()].push_back( + device->getTagName()); break; } } @@ -100,16 +112,64 @@ class PolicyConfig : private PolicyConfigData, public android::AudioPolicyConfig for (const auto& module : hwModules) { if (module->getDeclaredDevices().indexOf(device) >= 0) { mModulesWithDevicesNames.insert(module->getName()); + mAttachedDevicesPerModule[module->getName()].push_back( + device->getTagName()); break; } } } } } + std::string findAttachedDevice(const std::vector<std::string>& attachedDevices, + const std::set<std::string>& possibleDevices) const { + for (const auto& device : attachedDevices) { + if (possibleDevices.count(device)) return device; + } + return {}; + } + std::vector<std::string> getAttachedDevices(const std::string& moduleName) const { + if (auto iter = mAttachedDevicesPerModule.find(moduleName); + iter != mAttachedDevicesPerModule.end()) { + return iter->second; + } + return {}; + } + std::set<std::string> getSinkDevicesForMixPort(const std::string& moduleName, + const std::string& mixPortName) const { + std::set<std::string> result; + auto module = getModuleFromName(moduleName); + if (module != nullptr) { + for (const auto& route : module->getRoutes()) { + for (const auto& source : route->getSources()) { + if (source->getTagName() == mixPortName) { + result.insert(route->getSink()->getTagName()); + } + } + } + } + return result; + } + std::set<std::string> getSourceDevicesForMixPort(const std::string& moduleName, + const std::string& mixPortName) const { + std::set<std::string> result; + auto module = getModuleFromName(moduleName); + if (module != nullptr) { + for (const auto& route : module->getRoutes()) { + if (route->getSink()->getTagName() == mixPortName) { + const auto& sources = route->getSources(); + std::transform(sources.begin(), sources.end(), + std::inserter(result, result.end()), + [](const auto& source) { return source->getTagName(); }); + } + } + } + return result; + } const std::string mConfigFileName; status_t mStatus = android::NO_INIT; std::string mFilePath; sp<const android::HwModule> mPrimaryModule = nullptr; std::set<std::string> mModulesWithDevicesNames; + std::map<std::string, std::vector<std::string>> mAttachedDevicesPerModule; }; diff --git a/audio/core/all-versions/vts/functional/VtsHalAudioV6_0TargetTest.xml b/audio/core/all-versions/vts/functional/VtsHalAudioV6_0TargetTest.xml index f035bafa29..ae571258dc 100644 --- a/audio/core/all-versions/vts/functional/VtsHalAudioV6_0TargetTest.xml +++ b/audio/core/all-versions/vts/functional/VtsHalAudioV6_0TargetTest.xml @@ -34,5 +34,6 @@ <test class="com.android.tradefed.testtype.GTest" > <option name="native-test-device-path" value="/data/local/tmp" /> <option name="module-name" value="VtsHalAudioV6_0TargetTest" /> + <option name="native-test-timeout" value="5m" /> </test> </configuration> diff --git a/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml b/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml index 6635f3194a..55dbaf1e78 100644 --- a/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml +++ b/audio/core/all-versions/vts/functional/VtsHalAudioV7_0TargetTest.xml @@ -34,5 +34,6 @@ <test class="com.android.tradefed.testtype.GTest" > <option name="native-test-device-path" value="/data/local/tmp" /> <option name="module-name" value="VtsHalAudioV7_0TargetTest" /> + <option name="native-test-timeout" value="5m" /> </test> </configuration> diff --git a/audio/core/all-versions/vts/functional/tests/HalAudioV6_0GeneratorTest.xml b/audio/core/all-versions/vts/functional/tests/HalAudioV6_0GeneratorTest.xml index 0c85a05838..0230447ec6 100644 --- a/audio/core/all-versions/vts/functional/tests/HalAudioV6_0GeneratorTest.xml +++ b/audio/core/all-versions/vts/functional/tests/HalAudioV6_0GeneratorTest.xml @@ -24,6 +24,7 @@ <option name="cleanup" value="true" /> <option name="push" value="apm_config_no_vx.xml->/data/local/tmp/apm_config_no_vx.xml" /> <option name="push" value="apm_config_with_vx.xml->/data/local/tmp/apm_config_with_vx.xml" /> + <option name="push" value="apm_config_b_205808571_6_0.xml->/data/local/tmp/apm_config_b_205808571_6_0.xml" /> <option name="push" value="HalAudioV6_0GeneratorTest->/data/local/tmp/HalAudioV6_0GeneratorTest" /> </target_preparer> diff --git a/audio/core/all-versions/vts/functional/tests/HalAudioV7_0GeneratorTest.xml b/audio/core/all-versions/vts/functional/tests/HalAudioV7_0GeneratorTest.xml index 2e794554c8..0d8abd3b82 100644 --- a/audio/core/all-versions/vts/functional/tests/HalAudioV7_0GeneratorTest.xml +++ b/audio/core/all-versions/vts/functional/tests/HalAudioV7_0GeneratorTest.xml @@ -24,6 +24,8 @@ <option name="cleanup" value="true" /> <option name="push" value="apm_config_no_vx_7_0.xml->/data/local/tmp/apm_config_no_vx.xml" /> <option name="push" value="apm_config_with_vx_7_0.xml->/data/local/tmp/apm_config_with_vx.xml" /> + <option name="push" value="apm_config_b_204314749_7_0.xml->/data/local/tmp/apm_config_b_204314749_7_0.xml" /> + <option name="push" value="apm_config_b_205808571_7_0.xml->/data/local/tmp/apm_config_b_205808571_7_0.xml" /> <option name="push" value="HalAudioV7_0GeneratorTest->/data/local/tmp/HalAudioV7_0GeneratorTest" /> </target_preparer> diff --git a/audio/core/all-versions/vts/functional/tests/apm_config_b_204314749_7_0.xml b/audio/core/all-versions/vts/functional/tests/apm_config_b_204314749_7_0.xml new file mode 100644 index 0000000000..5bdca9aae2 --- /dev/null +++ b/audio/core/all-versions/vts/functional/tests/apm_config_b_204314749_7_0.xml @@ -0,0 +1,263 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<!-- Copyright (C) 2015 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. +--> + +<audioPolicyConfiguration version="7.0" xmlns:xi="http://www.w3.org/2001/XInclude"> + <!-- version section contains a “version” tag in the form “major.minor” e.g. version=”1.0” --> + + <!-- Global configuration Decalaration --> + <globalConfiguration speaker_drc_enabled="false"/> + + + <!-- Modules section: + There is one section per audio HW module present on the platform. + Each module section will contains two mandatory tags for audio HAL “halVersion” and “name”. + The module names are the same as in current .conf file: + “primary”, “A2DP”, “remote_submix”, “USB” + Each module will contain the following sections: + “devicePorts”: a list of device descriptors for all input and output devices accessible via this + module. + This contains both permanently attached devices and removable devices. + “mixPorts”: listing all output and input streams exposed by the audio HAL + “routes”: list of possible connections between input and output devices or between stream and + devices. + "route": is defined by an attribute: + -"type": <mux|mix> means all sources are mutual exclusive (mux) or can be mixed (mix) + -"sink": the sink involved in this route + -"sources": all the sources than can be connected to the sink via vis route + “attachedDevices”: permanently attached devices. + The attachedDevices section is a list of devices names. The names correspond to device names + defined in <devicePorts> section. + “defaultOutputDevice”: device to be used by default when no policy rule applies + --> + <modules> + <!-- Primary Audio HAL --> + <module name="primary" halVersion="3.0"> + <attachedDevices> + <item>Speaker</item> + <item>Built-In Mic</item> + <item>Built-In Back Mic</item> + <item>Echo Reference</item> + <item>Tuner</item> + </attachedDevices> + <defaultOutputDevice>Speaker</defaultOutputDevice> + <mixPorts> + <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + <mixPort name="tunnel pcm" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_HW_AV_SYNC"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="32000 44100 48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + <mixPort name="direct pcm" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="32000 44100 48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + <mixPort name="direct output" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT"> + <profile name=""/> + </mixPort> + <mixPort name="tunnel direct output" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_HW_AV_SYNC"> + <profile name=""/> + </mixPort> + <mixPort name="mmap_no_irq_out" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_MMAP_NOIRQ"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + <mixPort name="primary input" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000" + channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/> + </mixPort> + <mixPort name="tunnel a2dp" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_HW_AV_SYNC"> + <profile name=""/> + </mixPort> + <mixPort name="direct a2dp" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT"> + <profile name=""/> + </mixPort> + <mixPort name="echo reference" role="sink"> + <profile name="echo_reference" format="AUDIO_FORMAT_PCM_32_BIT" + samplingRates="48000" + channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/> + </mixPort> + <mixPort name="built-in mic" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_32_BIT" + samplingRates="16000" + channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/> + </mixPort> + <mixPort name="ble_in" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/> + </mixPort> + </mixPorts> + <devicePorts> + <!-- Output devices declaration, i.e. Sink DEVICE PORT --> + <devicePort tagName="Speaker" role="sink" type="AUDIO_DEVICE_OUT_SPEAKER"> + <gains> + <gain name="gain_1" mode="AUDIO_GAIN_MODE_JOINT" + minValueMB="-10000" + maxValueMB="0" + defaultValueMB="-6000" + stepValueMB="100"/> + </gains> + </devicePort> + <devicePort tagName="HDMI Out" type="AUDIO_DEVICE_OUT_AUX_DIGITAL" role="sink"> + </devicePort> + <devicePort tagName="Tuner" role="source" type="AUDIO_DEVICE_IN_TV_TUNER"> + <gains> + <gain name="gain_1" mode="AUDIO_GAIN_MODE_JOINT" + minValueMB="-10000" + maxValueMB="0" + defaultValueMB="-6000" + stepValueMB="100"/> + </gains> + </devicePort> + <devicePort tagName="Wired Headset" type="AUDIO_DEVICE_OUT_WIRED_HEADSET" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="Wired Headphones" type="AUDIO_DEVICE_OUT_WIRED_HEADPHONE" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="BT SCO" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/> + </devicePort> + <devicePort tagName="BT SCO Headset" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/> + </devicePort> + <devicePort tagName="BT A2DP Out" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="44100" + channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="BT A2DP Headphones" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="44100" + channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="BT A2DP Speaker" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="44100" + channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + + <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source" address="top"> + <profile name="" format="AUDIO_FORMAT_PCM_32_BIT" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000" + channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO AUDIO_CHANNEL_IN_FRONT_BACK"/> + </devicePort> + <devicePort tagName="Built-In Back Mic" type="AUDIO_DEVICE_IN_BACK_MIC" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000" + channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO AUDIO_CHANNEL_IN_FRONT_BACK"/> + </devicePort> + <devicePort tagName="Wired Headset Mic" type="AUDIO_DEVICE_IN_WIRED_HEADSET" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000" + channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO AUDIO_CHANNEL_IN_FRONT_BACK"/> + </devicePort> + <devicePort tagName="BT SCO Headset Mic" type="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/> + </devicePort> + <devicePort tagName="Echo Reference" type="AUDIO_DEVICE_IN_ECHO_REFERENCE" role="source"> + <profile name="echo_reference" format="AUDIO_FORMAT_PCM_32_BIT" + samplingRates="48000" + channelMasks="AUDIO_CHANNEL_IN_STEREO"/> + </devicePort> + <devicePort tagName="BLE-In" type="AUDIO_DEVICE_IN_BLUETOOTH_BLE" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/> + </devicePort> + </devicePorts> + <!-- route declaration, i.e. list all available sources for a given sink --> + <routes> + <route type="mix" sink="HDMI Out" + sources="primary output,tunnel pcm,direct output,Tuner,mmap_no_irq_out,tunnel direct output"/> + <route type="mix" sink="Speaker" + sources="primary output,tunnel pcm,direct pcm,BT SCO Headset Mic,Tuner,mmap_no_irq_out"/> + <route type="mix" sink="BT SCO" + sources="primary output,BT SCO Headset Mic,Tuner,mmap_no_irq_out"/> + <route type="mix" sink="BT SCO Headset" + sources="primary output,BT SCO Headset Mic,Tuner,mmap_no_irq_out"/> + <route type="mix" sink="Wired Headset" + sources="primary output,tunnel pcm,BT SCO Headset Mic,Tuner,mmap_no_irq_out"/> + <route type="mix" sink="Wired Headphones" + sources="primary output,tunnel pcm,BT SCO Headset Mic,Tuner,mmap_no_irq_out"/> + <route type="mix" sink="primary input" + sources="Built-In Back Mic,Wired Headset Mic,BT SCO Headset Mic,Tuner"/> + <route type="mix" sink="BT A2DP Out" + sources="primary output,tunnel a2dp,direct a2dp,Tuner,mmap_no_irq_out"/> + <route type="mix" sink="BT A2DP Headphones" + sources="primary output,tunnel a2dp,direct a2dp,Tuner,mmap_no_irq_out"/> + <route type="mix" sink="BT A2DP Speaker" + sources="primary output,tunnel a2dp,direct a2dp,Tuner,mmap_no_irq_out"/> + <route type="mix" sink="echo reference" + sources="Echo Reference"/> + <route type="mix" sink="built-in mic" + sources="Built-In Mic"/> + <route type="mix" sink="ble_in" + sources="BLE-In"/> + </routes> + + </module> + + <!-- A2dp Audio HAL --> + <!-- <xi:include href="a2dp_audio_policy_configuration.xml"/> --> + + <!-- Usb Audio HAL --> + <!-- <xi:include href="usb_audio_policy_configuration.xml"/> --> + + <!-- Remote Submix Audio HAL --> + <!-- <xi:include href="r_submix_audio_policy_configuration.xml"/> --> + + <!-- Hearing aid Audio HAL --> + <!-- <xi:include href="hearing_aid_audio_policy_configuration.xml"/> --> + + <!-- MSD Audio HAL (optional) --> + <!-- <xi:include href="msd_audio_policy_configuration.xml"/> --> + + </modules> + <!-- End of Modules section --> + + <!-- Volume section --> + + <!-- <xi:include href="audio_policy_volumes.xml"/> --> + <!-- <xi:include href="default_volume_tables.xml"/> --> + + <!-- End of Volume section --> + + <!-- Surround Sound configuration --> + + <surroundSound> + <!-- Each of the listed formats gets an entry in Surround Settings dialog on TV devices. + There must be a corresponding Java ENCODING_... constant defined in AudioFormat.java, + and a display name defined in AudioFormat.toDisplayName. For the formats that don't + need a dedicated Surrond Settings dialog entry, a subformats list has to be used. --> + <formats> + <format name="AUDIO_FORMAT_AC3" /> + <format name="AUDIO_FORMAT_E_AC3" /> + <format name="AUDIO_FORMAT_E_AC3_JOC" /> + <format name="AUDIO_FORMAT_DTS" /> + </formats> + </surroundSound> + + <!-- End of Surround Sound configuration --> + +</audioPolicyConfiguration> diff --git a/audio/core/all-versions/vts/functional/tests/apm_config_b_205808571_6_0.xml b/audio/core/all-versions/vts/functional/tests/apm_config_b_205808571_6_0.xml new file mode 100644 index 0000000000..0f7bf7f0a7 --- /dev/null +++ b/audio/core/all-versions/vts/functional/tests/apm_config_b_205808571_6_0.xml @@ -0,0 +1,451 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<!-- Copyright (c) 2016-2021, The Linux Foundation. All rights reserved + Not a Contribution. +--> +<!-- Copyright (C) 2015 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. +--> + +<audioPolicyConfiguration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude"> + <!-- version section contains a “version” tag in the form “major.minor” e.g. version=”1.0” --> + + <!-- Global configuration Decalaration --> + <globalConfiguration speaker_drc_enabled="true" call_screen_mode_supported="true"/> + + + <!-- Modules section: + There is one section per audio HW module present on the platform. + Each module section will contains two mandatory tags for audio HAL “halVersion” and “name”. + The module names are the same as in current .conf file: + “primary”, “A2DP”, “remote_submix”, “USB” + Each module will contain the following sections: + “devicePorts”: a list of device descriptors for all input and output devices accessible via this + module. + This contains both permanently attached devices and removable devices. + “mixPorts”: listing all output and input streams exposed by the audio HAL + “routes”: list of possible connections between input and output devices or between stream and + devices. + "route": is defined by an attribute: + -"type": <mux|mix> means all sources are mutual exclusive (mux) or can be mixed (mix) + -"sink": the sink involved in this route + -"sources": all the sources than can be connected to the sink via vis route + “attachedDevices”: permanently attached devices. + The attachedDevices section is a list of devices names. The names correspond to device names + defined in <devicePorts> section. + “defaultOutputDevice”: device to be used by default when no policy rule applies + --> + <modules> + <!-- Primary Audio HAL --> + <module name="primary" halVersion="2.0"> + <attachedDevices> + <item>Earpiece</item> + <item>Speaker</item> + <item>Telephony Tx</item> + <item>Built-In Mic</item> + <item>Built-In Back Mic</item> + <item>FM Tuner</item> + <item>Telephony Rx</item> + </attachedDevices> + <defaultOutputDevice>Speaker</defaultOutputDevice> + <mixPorts> + <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_FAST|AUDIO_OUTPUT_FLAG_PRIMARY"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + <mixPort name="raw" role="source" + flags="AUDIO_OUTPUT_FLAG_FAST|AUDIO_OUTPUT_FLAG_RAW"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + <mixPort name="haptics output" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO_HAPTIC_A"/> + </mixPort> + <mixPort name="deep_buffer" role="source" + flags="AUDIO_OUTPUT_FLAG_DEEP_BUFFER"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + <mixPort name="mmap_no_irq_out" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + <mixPort name="hifi_playback" role="source" /> + <mixPort name="compress_passthrough" role="source" + flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING"> + </mixPort> + <mixPort name="direct_pcm" role="source" + flags="AUDIO_OUTPUT_FLAG_DIRECT"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000" + channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/> + <profile name="" format="AUDIO_FORMAT_PCM_8_24_BIT" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000,352800,384000" + channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/> + <profile name="" format="AUDIO_FORMAT_PCM_24_BIT_PACKED" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000,352800,384000" + channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/> + <profile name="" format="AUDIO_FORMAT_PCM_32_BIT" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000,352800,384000" + channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/> + </mixPort> + <mixPort name="compressed_offload" role="source" + flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD|AUDIO_OUTPUT_FLAG_NON_BLOCKING"> + <profile name="" format="AUDIO_FORMAT_MP3" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/> + <profile name="" format="AUDIO_FORMAT_FLAC" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/> + <profile name="" format="AUDIO_FORMAT_ALAC" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000" + channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/> + <profile name="" format="AUDIO_FORMAT_APE" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/> + <profile name="" format="AUDIO_FORMAT_AAC_LC" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/> + <profile name="" format="AUDIO_FORMAT_AAC_HE_V1" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/> + <profile name="" format="AUDIO_FORMAT_AAC_HE_V2" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/> + <profile name="" format="AUDIO_FORMAT_DTS" + samplingRates="32000,44100,48000" + channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1"/> + <profile name="" format="AUDIO_FORMAT_DTS_HD" + samplingRates="32000,44100,48000,64000,88200,96000,128000,176400,192000" + channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/> + <profile name="" format="AUDIO_FORMAT_WMA" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000" + channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/> + <profile name="" format="AUDIO_FORMAT_WMA_PRO" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000" + channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_2POINT1,AUDIO_CHANNEL_OUT_QUAD,AUDIO_CHANNEL_OUT_PENTA,AUDIO_CHANNEL_OUT_5POINT1,AUDIO_CHANNEL_OUT_6POINT1,AUDIO_CHANNEL_OUT_7POINT1"/> + <profile name="" format="AUDIO_FORMAT_VORBIS" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/> + <profile name="" format="AUDIO_FORMAT_AAC_ADTS_LC" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/> + <profile name="" format="AUDIO_FORMAT_AAC_ADTS_HE_V1" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/> + <profile name="" format="AUDIO_FORMAT_AAC_ADTS_HE_V2" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO,AUDIO_CHANNEL_OUT_MONO"/> + </mixPort> + <mixPort name="voice_tx" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000,16000,48000" channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + <mixPort name="voip_rx" role="source" + flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_VOIP_RX"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000,16000,32000,48000" channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + <mixPort name="incall_music_uplink" role="source" + flags="AUDIO_OUTPUT_FLAG_INCALL_MUSIC"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000,16000,48000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + + <mixPort name="primary input" role="sink" maxOpenCount="2" maxActiveCount="2"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000" + channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/> + </mixPort> + <mixPort name="fast input" role="sink" + flags="AUDIO_INPUT_FLAG_FAST"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000" + channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/> + </mixPort> + <mixPort name="quad mic" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" + channelMasks="AUDIO_CHANNEL_INDEX_MASK_4"/> + </mixPort> + <mixPort name="voip_tx" role="sink" + flags="AUDIO_INPUT_FLAG_VOIP_TX"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000,16000,32000,48000" channelMasks="AUDIO_CHANNEL_IN_MONO"/> + </mixPort> + <mixPort name="usb_surround_sound" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,88200,96000,176400,192000" + channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK,AUDIO_CHANNEL_INDEX_MASK_3,AUDIO_CHANNEL_INDEX_MASK_4,AUDIO_CHANNEL_IN_5POINT1,AUDIO_CHANNEL_INDEX_MASK_6,AUDIO_CHANNEL_IN_7POINT1,AUDIO_CHANNEL_INDEX_MASK_8"/> + <profile name="" format="AUDIO_FORMAT_PCM_32_BIT" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,88200,96000,176400,192000" + channelMasks="AUDIO_CHANNEL_IN_5POINT1,AUDIO_CHANNEL_INDEX_MASK_6,AUDIO_CHANNEL_IN_7POINT1,AUDIO_CHANNEL_INDEX_MASK_8"/> + <profile name="" format="AUDIO_FORMAT_PCM_FLOAT" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,88200,96000,176400,192000" + channelMasks="AUDIO_CHANNEL_IN_5POINT1,AUDIO_CHANNEL_INDEX_MASK_6,AUDIO_CHANNEL_IN_7POINT1,AUDIO_CHANNEL_INDEX_MASK_8"/> + </mixPort> + <mixPort name="record_24" role="sink" maxOpenCount="2" maxActiveCount="2"> + <profile name="" format="AUDIO_FORMAT_PCM_24_BIT_PACKED" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,96000,192000" + channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK,AUDIO_CHANNEL_INDEX_MASK_3,AUDIO_CHANNEL_INDEX_MASK_4"/> + <profile name="" format="AUDIO_FORMAT_PCM_8_24_BIT" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,96000,192000" + channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK,AUDIO_CHANNEL_INDEX_MASK_3,AUDIO_CHANNEL_INDEX_MASK_4"/> + <profile name="" format="AUDIO_FORMAT_PCM_FLOAT" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000,96000,192000" + channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK,AUDIO_CHANNEL_INDEX_MASK_3,AUDIO_CHANNEL_INDEX_MASK_4"/> + </mixPort> + <mixPort name="voice_rx" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000,16000,48000" channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/> + </mixPort> + <mixPort name="mmap_no_irq_in" role="sink" flags="AUDIO_INPUT_FLAG_MMAP_NOIRQ"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000" + channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK,AUDIO_CHANNEL_INDEX_MASK_3"/> + </mixPort> + <mixPort name="hifi_input" role="sink" /> + </mixPorts> + + <devicePorts> + <!-- Output devices declaration, i.e. Sink DEVICE PORT --> + <devicePort tagName="Earpiece" type="AUDIO_DEVICE_OUT_EARPIECE" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_MONO"/> + </devicePort> + <devicePort tagName="Speaker" role="sink" type="AUDIO_DEVICE_OUT_SPEAKER" address=""> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="Wired Headset" type="AUDIO_DEVICE_OUT_WIRED_HEADSET" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="Wired Headphones" type="AUDIO_DEVICE_OUT_WIRED_HEADPHONE" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="Line" type="AUDIO_DEVICE_OUT_LINE" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="BT SCO" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/> + </devicePort> + <devicePort tagName="BT SCO Headset" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/> + </devicePort> + <devicePort tagName="BT SCO Car Kit" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/> + </devicePort> + <devicePort tagName="Telephony Tx" type="AUDIO_DEVICE_OUT_TELEPHONY_TX" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="HDMI" type="AUDIO_DEVICE_OUT_AUX_DIGITAL" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,128000,176400,192000"/> + </devicePort> + <devicePort tagName="Proxy" type="AUDIO_DEVICE_OUT_PROXY" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000,11025,16000,22050,32000,44100,48000,64000,88200,96000,128000,176400,192000"/> + </devicePort> + <devicePort tagName="FM" type="AUDIO_DEVICE_OUT_FM" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_MONO,AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="BT A2DP Out" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP" role="sink" + encodedFormats="AUDIO_FORMAT_SBC AUDIO_FORMAT_AAC AUDIO_FORMAT_APTX AUDIO_FORMAT_APTX_HD AUDIO_FORMAT_LDAC AUDIO_FORMAT_CELT AUDIO_FORMAT_APTX_ADAPTIVE AUDIO_FORMAT_APTX_TWSP VX_AUDIO_FORMAT_LC3"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="BT A2DP Headphones" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES" role="sink" + encodedFormats="AUDIO_FORMAT_SBC AUDIO_FORMAT_AAC AUDIO_FORMAT_APTX AUDIO_FORMAT_APTX_HD AUDIO_FORMAT_LDAC AUDIO_FORMAT_CELT AUDIO_FORMAT_APTX_ADAPTIVE AUDIO_FORMAT_APTX_TWSP VX_AUDIO_FORMAT_LC3"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="BT A2DP Speaker" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER" role="sink" + encodedFormats="AUDIO_FORMAT_SBC AUDIO_FORMAT_AAC AUDIO_FORMAT_APTX AUDIO_FORMAT_APTX_HD AUDIO_FORMAT_LDAC AUDIO_FORMAT_CELT AUDIO_FORMAT_APTX_ADAPTIVE AUDIO_FORMAT_APTX_TWSP VX_AUDIO_FORMAT_LC3"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="USB Device Out" type="AUDIO_DEVICE_OUT_USB_DEVICE" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="44100,48000,64000,88200,96000,128000,176400,192000"/> + </devicePort> + <devicePort tagName="USB Headset Out" type="AUDIO_DEVICE_OUT_USB_HEADSET" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="44100,48000,64000,88200,96000,128000,176400,192000"/> + </devicePort> + + <!-- Input devices declaration, i.e. Source DEVICE PORT --> + <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000" + channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/> + </devicePort> + <devicePort tagName="Built-In Back Mic" type="AUDIO_DEVICE_IN_BACK_MIC" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000" + channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/> + </devicePort> + <devicePort tagName="FM Tuner" type="AUDIO_DEVICE_IN_FM_TUNER" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" + channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/> + </devicePort> + <devicePort tagName="Wired Headset Mic" type="AUDIO_DEVICE_IN_WIRED_HEADSET" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000,11025,12000,16000,22050,24000,32000,44100,48000" + channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO,AUDIO_CHANNEL_IN_FRONT_BACK"/> + </devicePort> + <devicePort tagName="BT SCO Headset Mic" type="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000,16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/> + </devicePort> + <devicePort tagName="Telephony Rx" type="AUDIO_DEVICE_IN_TELEPHONY_RX" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000,16000,48000" channelMasks="AUDIO_CHANNEL_IN_MONO"/> + </devicePort> + <devicePort tagName="USB Device In" type="AUDIO_DEVICE_IN_USB_DEVICE" role="source"> + </devicePort> + <devicePort tagName="USB Headset In" type="AUDIO_DEVICE_IN_USB_HEADSET" role="source"> + </devicePort> + <devicePort tagName="A2DP In" type="AUDIO_DEVICE_IN_BLUETOOTH_A2DP" role="source" + encodedFormats="VX_AUDIO_FORMAT_LC3"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="44100,48000" channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/> + </devicePort> + + </devicePorts> + <!-- route declaration, i.e. list all available sources for a given sink --> + <routes> + <route type="mix" sink="Earpiece" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,mmap_no_irq_out,haptics output"/> + <route type="mix" sink="Speaker" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,mmap_no_irq_out,haptics output"/> + <route type="mix" sink="Wired Headset" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,mmap_no_irq_out,haptics output"/> + <route type="mix" sink="Wired Headphones" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,mmap_no_irq_out,haptics output"/> + <route type="mix" sink="Line" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,mmap_no_irq_out,haptics output"/> + <route type="mix" sink="HDMI" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,compress_passthrough,voip_rx,haptics output"/> + <route type="mix" sink="Proxy" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,haptics output"/> + <route type="mix" sink="FM" + sources="primary output"/> + <route type="mix" sink="BT SCO" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,haptics output"/> + <route type="mix" sink="BT SCO Headset" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,haptics output"/> + <route type="mix" sink="BT SCO Car Kit" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,haptics output"/> + <route type="mix" sink="USB Device Out" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,mmap_no_irq_out,hifi_playback,haptics output"/> + <route type="mix" sink="USB Headset Out" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,mmap_no_irq_out,hifi_playback,haptics output"/> + <route type="mix" sink="Telephony Tx" + sources="voice_tx,incall_music_uplink"/> + <route type="mix" sink="voice_rx" + sources="Telephony Rx"/> + <route type="mix" sink="primary input" + sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,BT SCO Headset Mic,FM Tuner,Telephony Rx,A2DP In"/> + <route type="mix" sink="usb_surround_sound" + sources="USB Device In,USB Headset In"/> + <route type="mix" sink="fast input" + sources="Built-In Mic,Built-In Back Mic,BT SCO Headset Mic,Wired Headset Mic"/> + <route type="mix" sink="quad mic" + sources="Built-In Mic,Built-In Back Mic,BT SCO Headset Mic,Wired Headset Mic"/> + <route type="mix" sink="voip_tx" + sources="Built-In Mic,Built-In Back Mic,BT SCO Headset Mic,USB Device In,USB Headset In,Wired Headset Mic"/> + <route type="mix" sink="record_24" + sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,A2DP In"/> + <route type="mix" sink="mmap_no_irq_in" + sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,USB Device In,USB Headset In"/> + <route type="mix" sink="BT A2DP Out" + sources="primary output,deep_buffer,direct_pcm,compressed_offload,voip_rx,haptics output"/> + <route type="mix" sink="BT A2DP Headphones" + sources="primary output,deep_buffer,direct_pcm,compressed_offload,voip_rx,haptics output"/> + <route type="mix" sink="BT A2DP Speaker" + sources="primary output,deep_buffer,direct_pcm,compressed_offload,voip_rx,haptics output"/> + <route type="mix" sink="hifi_input" sources="USB Device In,USB Headset In" /> + </routes> + + </module> + + <!-- A2DP Audio HAL --> + <module name="a2dp" halVersion="2.0"> + <mixPorts> + <mixPort name="a2dp input" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="44100,48000" channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/> + </mixPort> + </mixPorts> + + <devicePorts> + <devicePort tagName="BT A2DP In" type="AUDIO_DEVICE_IN_BLUETOOTH_A2DP" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="44100,48000" channelMasks="AUDIO_CHANNEL_IN_MONO,AUDIO_CHANNEL_IN_STEREO"/> + </devicePort> + </devicePorts> + + <routes> + <route type="mix" sink="a2dp input" + sources="BT A2DP In"/> + </routes> + </module> + + <!-- Usb Audio HAL --> + <module name="usb" halVersion="2.0"> + <mixPorts> + <mixPort name="usb_accessory output" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="44100" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + </mixPorts> + <devicePorts> + <devicePort tagName="USB Host Out" type="AUDIO_DEVICE_OUT_USB_ACCESSORY" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="44100" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + </devicePorts> + <routes> + <route type="mix" sink="USB Host Out" + sources="usb_accessory output"/> + </routes> + </module> + + <!-- Remote Submix Audio HAL --> + <!-- <xi:include href="/vendor/etc/r_submix_audio_policy_configuration.xml"/> --> + + <!-- Bluetooth Audio HAL for hearing aid --> + <!-- <xi:include href="/vendor/etc/bluetooth_qti_hearing_aid_audio_policy_configuration.xml"/> --> + + </modules> + <!-- End of Modules section --> + + <!-- Volume section --> + + <!-- <xi:include href="/vendor/etc/audio_policy_volumes.xml"/> --> + <!-- <xi:include href="/vendor/etc/default_volume_tables.xml"/> --> + + <!-- End of Volume section --> + +</audioPolicyConfiguration> diff --git a/audio/core/all-versions/vts/functional/tests/apm_config_b_205808571_7_0.xml b/audio/core/all-versions/vts/functional/tests/apm_config_b_205808571_7_0.xml new file mode 100644 index 0000000000..16427b6609 --- /dev/null +++ b/audio/core/all-versions/vts/functional/tests/apm_config_b_205808571_7_0.xml @@ -0,0 +1,446 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<!-- Copyright (c) 2016-2021, The Linux Foundation. All rights reserved + Not a Contribution. +--> +<!-- Copyright (C) 2015 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. +--> + +<audioPolicyConfiguration version="7.0" xmlns:xi="http://www.w3.org/2001/XInclude"> + <!-- version section contains a “version” tag in the form “major.minor” e.g. version=”1.0” --> + + <!-- Global configuration Decalaration --> + <globalConfiguration speaker_drc_enabled="true" call_screen_mode_supported="true"/> + + + <!-- Modules section: + There is one section per audio HW module present on the platform. + Each module section will contains two mandatory tags for audio HAL “halVersion” and “name”. + The module names are the same as in current .conf file: + “primary”, “A2DP”, “remote_submix”, “USB” + Each module will contain the following sections: + “devicePorts”: a list of device descriptors for all input and output devices accessible via this + module. + This contains both permanently attached devices and removable devices. + “mixPorts”: listing all output and input streams exposed by the audio HAL + “routes”: list of possible connections between input and output devices or between stream and + devices. + "route": is defined by an attribute: + -"type": <mux|mix> means all sources are mutual exclusive (mux) or can be mixed (mix) + -"sink": the sink involved in this route + -"sources": all the sources than can be connected to the sink via vis route + “attachedDevices”: permanently attached devices. + The attachedDevices section is a list of devices names. The names correspond to device names + defined in <devicePorts> section. + “defaultOutputDevice”: device to be used by default when no policy rule applies + --> + <modules> + <!-- Primary Audio HAL --> + <module name="primary" halVersion="2.0"> + <attachedDevices> + <item>Earpiece</item> + <item>Speaker</item> + <item>Telephony Tx</item> + <item>Built-In Mic</item> + <item>Built-In Back Mic</item> + <item>FM Tuner</item> + <item>Telephony Rx</item> + </attachedDevices> + <defaultOutputDevice>Speaker</defaultOutputDevice> + <mixPorts> + <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_FAST AUDIO_OUTPUT_FLAG_PRIMARY"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + <mixPort name="raw" role="source" + flags="AUDIO_OUTPUT_FLAG_FAST AUDIO_OUTPUT_FLAG_RAW"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + <mixPort name="haptics output" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO_HAPTIC_A"/> + </mixPort> + <mixPort name="deep_buffer" role="source" + flags="AUDIO_OUTPUT_FLAG_DEEP_BUFFER"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + <mixPort name="mmap_no_irq_out" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_MMAP_NOIRQ"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + <mixPort name="hifi_playback" role="source" /> + <mixPort name="compress_passthrough" role="source" + flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD AUDIO_OUTPUT_FLAG_NON_BLOCKING"> + </mixPort> + <mixPort name="direct_pcm" role="source" + flags="AUDIO_OUTPUT_FLAG_DIRECT"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 64000 88200 96000 128000 176400 192000" + channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_2POINT1 AUDIO_CHANNEL_OUT_QUAD AUDIO_CHANNEL_OUT_PENTA AUDIO_CHANNEL_OUT_5POINT1 AUDIO_CHANNEL_OUT_6POINT1 AUDIO_CHANNEL_OUT_7POINT1"/> + <profile name="" format="AUDIO_FORMAT_PCM_8_24_BIT" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 64000 88200 96000 128000 176400 192000 352800 384000" + channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_2POINT1 AUDIO_CHANNEL_OUT_QUAD AUDIO_CHANNEL_OUT_PENTA AUDIO_CHANNEL_OUT_5POINT1 AUDIO_CHANNEL_OUT_6POINT1 AUDIO_CHANNEL_OUT_7POINT1"/> + <profile name="" format="AUDIO_FORMAT_PCM_24_BIT_PACKED" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 64000 88200 96000 128000 176400 192000 352800 384000" + channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_2POINT1 AUDIO_CHANNEL_OUT_QUAD AUDIO_CHANNEL_OUT_PENTA AUDIO_CHANNEL_OUT_5POINT1 AUDIO_CHANNEL_OUT_6POINT1 AUDIO_CHANNEL_OUT_7POINT1"/> + <profile name="" format="AUDIO_FORMAT_PCM_32_BIT" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 64000 88200 96000 128000 176400 192000 352800 384000" + channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_2POINT1 AUDIO_CHANNEL_OUT_QUAD AUDIO_CHANNEL_OUT_PENTA AUDIO_CHANNEL_OUT_5POINT1 AUDIO_CHANNEL_OUT_6POINT1 AUDIO_CHANNEL_OUT_7POINT1"/> + </mixPort> + <mixPort name="compressed_offload" role="source" + flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD AUDIO_OUTPUT_FLAG_NON_BLOCKING"> + <profile name="" format="AUDIO_FORMAT_MP3" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/> + <profile name="" format="AUDIO_FORMAT_FLAC" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 64000 88200 96000 128000 176400 192000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/> + <profile name="" format="AUDIO_FORMAT_ALAC" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 64000 88200 96000 128000 176400 192000" + channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_2POINT1 AUDIO_CHANNEL_OUT_QUAD AUDIO_CHANNEL_OUT_PENTA AUDIO_CHANNEL_OUT_5POINT1 AUDIO_CHANNEL_OUT_6POINT1 AUDIO_CHANNEL_OUT_7POINT1"/> + <profile name="" format="AUDIO_FORMAT_APE" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 64000 88200 96000 128000 176400 192000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/> + <profile name="" format="AUDIO_FORMAT_AAC_LC" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 64000 88200 96000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/> + <profile name="" format="AUDIO_FORMAT_AAC_HE_V1" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 64000 88200 96000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/> + <profile name="" format="AUDIO_FORMAT_AAC_HE_V2" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 64000 88200 96000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/> + <profile name="" format="AUDIO_FORMAT_DTS" + samplingRates="32000 44100 48000" + channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_2POINT1 AUDIO_CHANNEL_OUT_QUAD AUDIO_CHANNEL_OUT_PENTA AUDIO_CHANNEL_OUT_5POINT1"/> + <profile name="" format="AUDIO_FORMAT_DTS_HD" + samplingRates="32000 44100 48000 64000 88200 96000 128000 176400 192000" + channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_2POINT1 AUDIO_CHANNEL_OUT_QUAD AUDIO_CHANNEL_OUT_PENTA AUDIO_CHANNEL_OUT_5POINT1 AUDIO_CHANNEL_OUT_6POINT1 AUDIO_CHANNEL_OUT_7POINT1"/> + <profile name="" format="AUDIO_FORMAT_WMA" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000" + channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_2POINT1 AUDIO_CHANNEL_OUT_QUAD AUDIO_CHANNEL_OUT_PENTA AUDIO_CHANNEL_OUT_5POINT1 AUDIO_CHANNEL_OUT_6POINT1 AUDIO_CHANNEL_OUT_7POINT1"/> + <profile name="" format="AUDIO_FORMAT_WMA_PRO" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 64000 88200 96000" + channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_2POINT1 AUDIO_CHANNEL_OUT_QUAD AUDIO_CHANNEL_OUT_PENTA AUDIO_CHANNEL_OUT_5POINT1 AUDIO_CHANNEL_OUT_6POINT1 AUDIO_CHANNEL_OUT_7POINT1"/> + <profile name="" format="AUDIO_FORMAT_VORBIS" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 64000 88200 96000 128000 176400 192000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/> + <profile name="" format="AUDIO_FORMAT_AAC_ADTS_LC" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 64000 88200 96000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/> + <profile name="" format="AUDIO_FORMAT_AAC_ADTS_HE_V1" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 64000 88200 96000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/> + <profile name="" format="AUDIO_FORMAT_AAC_ADTS_HE_V2" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 64000 88200 96000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/> + </mixPort> + <mixPort name="voice_tx" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 16000 48000" channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + <mixPort name="voip_rx" role="source" + flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_VOIP_RX"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 16000 32000 48000" channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + <mixPort name="incall_music_uplink" role="source" + flags="AUDIO_OUTPUT_FLAG_INCALL_MUSIC"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 16000 48000" + channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + + <mixPort name="primary input" role="sink" maxOpenCount="2" maxActiveCount="2"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000" + channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO AUDIO_CHANNEL_IN_FRONT_BACK"/> + </mixPort> + <mixPort name="fast input" role="sink" + flags="AUDIO_INPUT_FLAG_FAST"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000" + channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO AUDIO_CHANNEL_IN_FRONT_BACK"/> + </mixPort> + <mixPort name="quad mic" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" + channelMasks="AUDIO_CHANNEL_INDEX_MASK_4"/> + </mixPort> + <mixPort name="voip_tx" role="sink" + flags="AUDIO_INPUT_FLAG_VOIP_TX"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 16000 32000 48000" channelMasks="AUDIO_CHANNEL_IN_MONO"/> + </mixPort> + <mixPort name="usb_surround_sound" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 88200 96000 176400 192000" + channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO AUDIO_CHANNEL_IN_FRONT_BACK AUDIO_CHANNEL_INDEX_MASK_3 AUDIO_CHANNEL_INDEX_MASK_4 AUDIO_CHANNEL_IN_5POINT1 AUDIO_CHANNEL_INDEX_MASK_6"/> + <profile name="" format="AUDIO_FORMAT_PCM_32_BIT" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 88200 96000 176400 192000" + channelMasks="AUDIO_CHANNEL_IN_5POINT1 AUDIO_CHANNEL_INDEX_MASK_6"/> + <profile name="" format="AUDIO_FORMAT_PCM_FLOAT" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 88200 96000 176400 192000" + channelMasks="AUDIO_CHANNEL_IN_5POINT1 AUDIO_CHANNEL_INDEX_MASK_6"/> + </mixPort> + <mixPort name="record_24" role="sink" maxOpenCount="2" maxActiveCount="2"> + <profile name="" format="AUDIO_FORMAT_PCM_24_BIT_PACKED" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 96000 192000" + channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO AUDIO_CHANNEL_IN_FRONT_BACK AUDIO_CHANNEL_INDEX_MASK_3 AUDIO_CHANNEL_INDEX_MASK_4"/> + <profile name="" format="AUDIO_FORMAT_PCM_8_24_BIT" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 96000 192000" + channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO AUDIO_CHANNEL_IN_FRONT_BACK AUDIO_CHANNEL_INDEX_MASK_3 AUDIO_CHANNEL_INDEX_MASK_4"/> + <profile name="" format="AUDIO_FORMAT_PCM_FLOAT" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 96000 192000" + channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO AUDIO_CHANNEL_IN_FRONT_BACK AUDIO_CHANNEL_INDEX_MASK_3 AUDIO_CHANNEL_INDEX_MASK_4"/> + </mixPort> + <mixPort name="voice_rx" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 16000 48000" channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/> + </mixPort> + <mixPort name="mmap_no_irq_in" role="sink" flags="AUDIO_INPUT_FLAG_MMAP_NOIRQ"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000" + channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO AUDIO_CHANNEL_IN_FRONT_BACK AUDIO_CHANNEL_INDEX_MASK_3"/> + </mixPort> + <mixPort name="hifi_input" role="sink" /> + </mixPorts> + + <devicePorts> + <!-- Output devices declaration, i.e. Sink DEVICE PORT --> + <devicePort tagName="Earpiece" type="AUDIO_DEVICE_OUT_EARPIECE" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_IN_MONO"/> + </devicePort> + <devicePort tagName="Speaker" role="sink" type="AUDIO_DEVICE_OUT_SPEAKER" address=""> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="Wired Headset" type="AUDIO_DEVICE_OUT_WIRED_HEADSET" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="Wired Headphones" type="AUDIO_DEVICE_OUT_WIRED_HEADPHONE" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="Line" type="AUDIO_DEVICE_OUT_LINE" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="BT SCO" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/> + </devicePort> + <devicePort tagName="BT SCO Headset" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/> + </devicePort> + <devicePort tagName="BT SCO Car Kit" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 16000" channelMasks="AUDIO_CHANNEL_OUT_MONO"/> + </devicePort> + <devicePort tagName="Telephony Tx" type="AUDIO_DEVICE_OUT_TELEPHONY_TX" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 16000" channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="HDMI" type="AUDIO_DEVICE_OUT_AUX_DIGITAL" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 11025 16000 22050 32000 44100 48000 64000 88200 96000 128000 176400 192000"/> + </devicePort> + <devicePort tagName="Proxy" type="AUDIO_DEVICE_OUT_PROXY" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 11025 16000 22050 32000 44100 48000 64000 88200 96000 128000 176400 192000"/> + </devicePort> + <devicePort tagName="FM" type="AUDIO_DEVICE_OUT_FM" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_MONO AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="BT A2DP Out" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP" role="sink" + encodedFormats="AUDIO_FORMAT_SBC AUDIO_FORMAT_AAC AUDIO_FORMAT_APTX AUDIO_FORMAT_APTX_HD AUDIO_FORMAT_LDAC AUDIO_FORMAT_CELT AUDIO_FORMAT_APTX_ADAPTIVE AUDIO_FORMAT_APTX_TWSP VX_AUDIO_FORMAT_LC3"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="BT A2DP Headphones" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES" role="sink" + encodedFormats="AUDIO_FORMAT_SBC AUDIO_FORMAT_AAC AUDIO_FORMAT_APTX AUDIO_FORMAT_APTX_HD AUDIO_FORMAT_LDAC AUDIO_FORMAT_CELT AUDIO_FORMAT_APTX_ADAPTIVE AUDIO_FORMAT_APTX_TWSP VX_AUDIO_FORMAT_LC3"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="BT A2DP Speaker" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER" role="sink" + encodedFormats="AUDIO_FORMAT_SBC AUDIO_FORMAT_AAC AUDIO_FORMAT_APTX AUDIO_FORMAT_APTX_HD AUDIO_FORMAT_LDAC AUDIO_FORMAT_CELT AUDIO_FORMAT_APTX_ADAPTIVE AUDIO_FORMAT_APTX_TWSP VX_AUDIO_FORMAT_LC3"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + <devicePort tagName="USB Device Out" type="AUDIO_DEVICE_OUT_USB_DEVICE" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="44100 48000 64000 88200 96000 128000 176400 192000"/> + </devicePort> + <devicePort tagName="USB Headset Out" type="AUDIO_DEVICE_OUT_USB_HEADSET" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="44100 48000 64000 88200 96000 128000 176400 192000"/> + </devicePort> + + <!-- Input devices declaration, i.e. Source DEVICE PORT --> + <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000" + channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO AUDIO_CHANNEL_IN_FRONT_BACK"/> + </devicePort> + <devicePort tagName="Built-In Back Mic" type="AUDIO_DEVICE_IN_BACK_MIC" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000" + channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO AUDIO_CHANNEL_IN_FRONT_BACK"/> + </devicePort> + <devicePort tagName="FM Tuner" type="AUDIO_DEVICE_IN_FM_TUNER" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="48000" + channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/> + </devicePort> + <devicePort tagName="Wired Headset Mic" type="AUDIO_DEVICE_IN_WIRED_HEADSET" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000" + channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO AUDIO_CHANNEL_IN_FRONT_BACK"/> + </devicePort> + <devicePort tagName="BT SCO Headset Mic" type="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 16000" channelMasks="AUDIO_CHANNEL_IN_MONO"/> + </devicePort> + <devicePort tagName="Telephony Rx" type="AUDIO_DEVICE_IN_TELEPHONY_RX" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="8000 16000 48000" channelMasks="AUDIO_CHANNEL_IN_MONO"/> + </devicePort> + <devicePort tagName="USB Device In" type="AUDIO_DEVICE_IN_USB_DEVICE" role="source"> + </devicePort> + <devicePort tagName="USB Headset In" type="AUDIO_DEVICE_IN_USB_HEADSET" role="source"> + </devicePort> + <devicePort tagName="A2DP In" type="AUDIO_DEVICE_IN_BLUETOOTH_A2DP" role="source" + encodedFormats="VX_AUDIO_FORMAT_LC3"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="44100 48000" channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/> + </devicePort> + + </devicePorts> + <!-- route declaration, i.e. list all available sources for a given sink --> + <routes> + <route type="mix" sink="Earpiece" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,mmap_no_irq_out,haptics output"/> + <route type="mix" sink="Speaker" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,mmap_no_irq_out,haptics output"/> + <route type="mix" sink="Wired Headset" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,mmap_no_irq_out,haptics output"/> + <route type="mix" sink="Wired Headphones" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,mmap_no_irq_out,haptics output"/> + <route type="mix" sink="Line" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,mmap_no_irq_out,haptics output"/> + <route type="mix" sink="HDMI" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,compress_passthrough,voip_rx,haptics output"/> + <route type="mix" sink="Proxy" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,haptics output"/> + <route type="mix" sink="FM" + sources="primary output"/> + <route type="mix" sink="BT SCO" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,haptics output"/> + <route type="mix" sink="BT SCO Headset" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,haptics output"/> + <route type="mix" sink="BT SCO Car Kit" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,haptics output"/> + <route type="mix" sink="USB Device Out" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,mmap_no_irq_out,hifi_playback,haptics output"/> + <route type="mix" sink="USB Headset Out" + sources="primary output,raw,deep_buffer,direct_pcm,compressed_offload,voip_rx,mmap_no_irq_out,hifi_playback,haptics output"/> + <route type="mix" sink="Telephony Tx" + sources="voice_tx,incall_music_uplink"/> + <route type="mix" sink="voice_rx" + sources="Telephony Rx"/> + <route type="mix" sink="primary input" + sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,BT SCO Headset Mic,FM Tuner,Telephony Rx,A2DP In"/> + <route type="mix" sink="usb_surround_sound" + sources="USB Device In,USB Headset In"/> + <route type="mix" sink="fast input" + sources="Built-In Mic,Built-In Back Mic,BT SCO Headset Mic,Wired Headset Mic"/> + <route type="mix" sink="quad mic" + sources="Built-In Mic,Built-In Back Mic,BT SCO Headset Mic,Wired Headset Mic"/> + <route type="mix" sink="voip_tx" + sources="Built-In Mic,Built-In Back Mic,BT SCO Headset Mic,USB Device In,USB Headset In,Wired Headset Mic"/> + <route type="mix" sink="record_24" + sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,A2DP In"/> + <route type="mix" sink="mmap_no_irq_in" + sources="Built-In Mic,Built-In Back Mic,Wired Headset Mic,USB Device In,USB Headset In"/> + <route type="mix" sink="BT A2DP Out" + sources="primary output,deep_buffer,direct_pcm,compressed_offload,voip_rx,haptics output"/> + <route type="mix" sink="BT A2DP Headphones" + sources="primary output,deep_buffer,direct_pcm,compressed_offload,voip_rx,haptics output"/> + <route type="mix" sink="BT A2DP Speaker" + sources="primary output,deep_buffer,direct_pcm,compressed_offload,voip_rx,haptics output"/> + <route type="mix" sink="hifi_input" sources="USB Device In,USB Headset In" /> + </routes> + + </module> + + <!-- A2DP Audio HAL --> + <module name="a2dp" halVersion="2.0"> + <mixPorts> + <mixPort name="a2dp input" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="44100 48000" channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/> + </mixPort> + </mixPorts> + + <devicePorts> + <devicePort tagName="BT A2DP In" type="AUDIO_DEVICE_IN_BLUETOOTH_A2DP" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="44100 48000" channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/> + </devicePort> + </devicePorts> + + <routes> + <route type="mix" sink="a2dp input" + sources="BT A2DP In"/> + </routes> + </module> + + <!-- Usb Audio HAL --> + <module name="usb" halVersion="2.0"> + <mixPorts> + <mixPort name="usb_accessory output" role="source"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="44100" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </mixPort> + </mixPorts> + <devicePorts> + <devicePort tagName="USB Host Out" type="AUDIO_DEVICE_OUT_USB_ACCESSORY" role="sink"> + <profile name="" format="AUDIO_FORMAT_PCM_16_BIT" + samplingRates="44100" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/> + </devicePort> + </devicePorts> + <routes> + <route type="mix" sink="USB Host Out" + sources="usb_accessory output"/> + </routes> + </module> + + <!-- Remote Submix Audio HAL --> + + <!-- Bluetooth Audio HAL for hearing aid --> + + </modules> + <!-- End of Modules section --> + + <!-- Volume section --> + + <!-- End of Volume section --> + +</audioPolicyConfiguration> diff --git a/audio/core/all-versions/vts/functional/tests/generators_tests.cpp b/audio/core/all-versions/vts/functional/tests/generators_tests.cpp index 583ff01fc2..3fdd8e6086 100644 --- a/audio/core/all-versions/vts/functional/tests/generators_tests.cpp +++ b/audio/core/all-versions/vts/functional/tests/generators_tests.cpp @@ -128,5 +128,46 @@ TEST_P(GeneratorsTest, ValidateConfigs) { } // Target file names are the same for all versions, see 'HalAudioVx_0GeneratorTest.xml' test configs +// clang-format off INSTANTIATE_TEST_SUITE_P(Generators, GeneratorsTest, - ::testing::Values("apm_config_no_vx.xml", "apm_config_with_vx.xml")); + ::testing::Values("apm_config_no_vx.xml", "apm_config_with_vx.xml" +#if MAJOR_VERSION == 6 + , "apm_config_b_205808571_6_0.xml" +#elif MAJOR_VERSION == 7 + , "apm_config_b_204314749_7_0.xml" + , "apm_config_b_205808571_7_0.xml" +#endif + )); +// clang-format on + +TEST(GeneratorsDeviceTest, AttachedDevicesOnly) { + static const std::string kTestFile = + "apm_config_b_205808571_" STRINGIFY(MAJOR_VERSION) "_0.xml"; + ASSERT_TRUE(PolicyConfigManager::getInstance().init(kDataDir, kTestFile)); + EXPECT_NE(nullptr, getCachedPolicyConfig().getPrimaryModule()); + const auto allInConfigs = generateInputDeviceConfigParameters(false /*oneProfilePerDevice*/); + EXPECT_FALSE(allInConfigs.empty()); + for (const auto& configParam : allInConfigs) { + const AudioConfig& config = std::get<PARAM_CONFIG>(configParam); + // The config contains multichannel masks for mixPort connected to + // input devicePorts that are not attached. These multichannel masks must + // not appear among generated masks. + const uint32_t channelCount = +#if MAJOR_VERSION == 6 + audio_channel_count_from_in_mask( + static_cast<audio_channel_mask_t>(config.channelMask)); +#elif MAJOR_VERSION == 7 + xsd::getChannelCount(config.base.channelMask); +#endif + EXPECT_TRUE(channelCount <= 4) << "Unexpected channel count: " << channelCount << " " << +#if MAJOR_VERSION == 6 + ::testing::PrintToString(config.format) << ", " + << ::testing::PrintToString(config.sampleRateHz) << ", " + << ::testing::PrintToString(config.channelMask); +#elif MAJOR_VERSION == 7 + ::testing::PrintToString(config.base.format) << ", " + << ::testing::PrintToString(config.base.sampleRateHz) << ", " + << ::testing::PrintToString(config.base.channelMask); +#endif + } +} diff --git a/automotive/can/1.0/default/Android.bp b/automotive/can/1.0/default/Android.bp index c0c17e27f5..163fdb7265 100644 --- a/automotive/can/1.0/default/Android.bp +++ b/automotive/can/1.0/default/Android.bp @@ -64,4 +64,5 @@ cc_binary { "android.hardware.automotive@libc++fs", "libnl++", ], + vintf_fragments: ["manifest_android.hardware.automotive.can@1.0.xml"], } diff --git a/automotive/can/1.0/default/manifest_android.hardware.automotive.can@1.0.xml b/automotive/can/1.0/default/manifest_android.hardware.automotive.can@1.0.xml new file mode 100644 index 0000000000..2078ce54df --- /dev/null +++ b/automotive/can/1.0/default/manifest_android.hardware.automotive.can@1.0.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright (C) 2020 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. +--> +<manifest version="1.0" type="device" > + <hal format="hidl"> + <name>android.hardware.automotive.can</name> + <transport>hwbinder</transport> + <fqname>@1.0::ICanController/socketcan</fqname> + </hal> +</manifest> diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp index 8cc18822f2..1216d36eda 100644 --- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp +++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp @@ -79,19 +79,24 @@ using IEvsCamera_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsCamera; using IEvsDisplay_1_0 = ::android::hardware::automotive::evs::V1_0::IEvsDisplay; using IEvsDisplay_1_1 = ::android::hardware::automotive::evs::V1_1::IEvsDisplay; +namespace { + /* * Plese note that this is different from what is defined in * libhardware/modules/camera/3_4/metadata/types.h; this has one additional * field to store a framerate. */ -const size_t kStreamCfgSz = 5; typedef struct { + int32_t id; int32_t width; int32_t height; int32_t format; int32_t direction; int32_t framerate; } RawStreamConfig; +constexpr const size_t kStreamCfgSz = sizeof(RawStreamConfig) / sizeof(int32_t); + +} // anonymous namespace // The main test class for EVS @@ -236,6 +241,28 @@ protected: return physicalCameras; } + Stream getFirstStreamConfiguration(camera_metadata_t* metadata) { + Stream targetCfg = {}; + camera_metadata_entry_t streamCfgs; + if (!find_camera_metadata_entry(metadata, + ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, + &streamCfgs)) { + // Stream configurations are found in metadata + RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32); + for (unsigned offset = 0; offset < streamCfgs.count; offset += kStreamCfgSz) { + if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT && + ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) { + targetCfg.width = ptr->width; + targetCfg.height = ptr->height; + targetCfg.format = static_cast<PixelFormat>(ptr->format); + break; + } + ++ptr; + } + } + + return targetCfg; + } sp<IEvsEnumerator> pEnumerator; // Every test needs access to the service std::vector<CameraDesc> cameraInfo; // Empty unless/until loadCameraList() is called @@ -265,10 +292,6 @@ TEST_P(EvsHidlTest, CameraOpenClean) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Open and close each camera twice for (auto&& cam: cameraInfo) { bool isLogicalCam = false; @@ -278,8 +301,14 @@ TEST_P(EvsHidlTest, CameraOpenClean) { continue; } + // Read a target resolution from the metadata + Stream targetCfg = + getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data())); + ASSERT_GT(targetCfg.width, 0); + ASSERT_GT(targetCfg.height, 0); + for (int pass = 0; pass < 2; pass++) { - sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg); + sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg); ASSERT_NE(pCam, nullptr); for (auto&& devName : devices) { @@ -343,10 +372,6 @@ TEST_P(EvsHidlTest, CameraOpenAggressive) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Open and close each camera twice for (auto&& cam: cameraInfo) { bool isLogicalCam = false; @@ -356,10 +381,14 @@ TEST_P(EvsHidlTest, CameraOpenAggressive) { continue; } + // Read a target resolution from the metadata + Stream targetCfg = + getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data())); + ASSERT_GT(targetCfg.width, 0); + ASSERT_GT(targetCfg.height, 0); + activeCameras.clear(); - sp<IEvsCamera_1_1> pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) - .withDefault(nullptr); + sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg); ASSERT_NE(pCam, nullptr); // Store a camera handle for a clean-up @@ -372,9 +401,7 @@ TEST_P(EvsHidlTest, CameraOpenAggressive) { } ); - sp<IEvsCamera_1_1> pCam2 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) - .withDefault(nullptr); + sp<IEvsCamera_1_1> pCam2 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg); ASSERT_NE(pCam2, nullptr); // Store a camera handle for a clean-up @@ -422,10 +449,6 @@ TEST_P(EvsHidlTest, CameraStreamPerformance) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Test each reported camera for (auto&& cam: cameraInfo) { bool isLogicalCam = false; @@ -435,9 +458,13 @@ TEST_P(EvsHidlTest, CameraStreamPerformance) { continue; } - sp<IEvsCamera_1_1> pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) - .withDefault(nullptr); + // Read a target resolution from the metadata + Stream targetCfg = + getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data())); + ASSERT_GT(targetCfg.width, 0); + ASSERT_GT(targetCfg.height, 0); + + sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg); ASSERT_NE(pCam, nullptr); // Store a camera handle for a clean-up @@ -519,10 +546,6 @@ TEST_P(EvsHidlTest, CameraStreamBuffering) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Test each reported camera for (auto&& cam: cameraInfo) { bool isLogicalCam = false; @@ -532,9 +555,13 @@ TEST_P(EvsHidlTest, CameraStreamBuffering) { continue; } - sp<IEvsCamera_1_1> pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) - .withDefault(nullptr); + // Read a target resolution from the metadata + Stream targetCfg = + getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data())); + ASSERT_GT(targetCfg.width, 0); + ASSERT_GT(targetCfg.height, 0); + + sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg); ASSERT_NE(pCam, nullptr); // Store a camera handle for a clean-up @@ -601,10 +628,6 @@ TEST_P(EvsHidlTest, CameraToDisplayRoundTrip) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Request available display IDs uint8_t targetDisplayId = 0; pEnumerator->getDisplayIdList([&targetDisplayId](auto ids) { @@ -642,9 +665,13 @@ TEST_P(EvsHidlTest, CameraToDisplayRoundTrip) { continue; } - sp<IEvsCamera_1_1> pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) - .withDefault(nullptr); + // Read a target resolution from the metadata + Stream targetCfg = + getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data())); + ASSERT_GT(targetCfg.width, 0); + ASSERT_GT(targetCfg.height, 0); + + sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg); ASSERT_NE(pCam, nullptr); // Store a camera handle for a clean-up @@ -708,24 +735,22 @@ TEST_P(EvsHidlTest, MultiCameraStream) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Test each reported camera for (auto&& cam: cameraInfo) { + // Read a target resolution from the metadata + Stream targetCfg = + getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data())); + ASSERT_GT(targetCfg.width, 0); + ASSERT_GT(targetCfg.height, 0); + // Create two camera clients. - sp<IEvsCamera_1_1> pCam0 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) - .withDefault(nullptr); + sp<IEvsCamera_1_1> pCam0 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg); ASSERT_NE(pCam0, nullptr); // Store a camera handle for a clean-up activeCameras.push_back(pCam0); - sp<IEvsCamera_1_1> pCam1 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) - .withDefault(nullptr); + sp<IEvsCamera_1_1> pCam1 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg); ASSERT_NE(pCam1, nullptr); // Store a camera handle for a clean-up @@ -812,10 +837,6 @@ TEST_P(EvsHidlTest, CameraParameter) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Test each reported camera Return<EvsResult> result = EvsResult::OK; for (auto&& cam: cameraInfo) { @@ -828,10 +849,14 @@ TEST_P(EvsHidlTest, CameraParameter) { continue; } + // Read a target resolution from the metadata + Stream targetCfg = + getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data())); + ASSERT_GT(targetCfg.width, 0); + ASSERT_GT(targetCfg.height, 0); + // Create a camera client - sp<IEvsCamera_1_1> pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) - .withDefault(nullptr); + sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg); ASSERT_NE(pCam, nullptr); // Store a camera @@ -961,10 +986,6 @@ TEST_P(EvsHidlTest, CameraPrimaryClientRelease) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Test each reported camera for (auto&& cam: cameraInfo) { bool isLogicalCam = false; @@ -976,18 +997,20 @@ TEST_P(EvsHidlTest, CameraPrimaryClientRelease) { continue; } + // Read a target resolution from the metadata + Stream targetCfg = + getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data())); + ASSERT_GT(targetCfg.width, 0); + ASSERT_GT(targetCfg.height, 0); + // Create two camera clients. - sp<IEvsCamera_1_1> pCamPrimary = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) - .withDefault(nullptr); + sp<IEvsCamera_1_1> pCamPrimary = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg); ASSERT_NE(pCamPrimary, nullptr); // Store a camera handle for a clean-up activeCameras.push_back(pCamPrimary); - sp<IEvsCamera_1_1> pCamSecondary = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) - .withDefault(nullptr); + sp<IEvsCamera_1_1> pCamSecondary = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg); ASSERT_NE(pCamSecondary, nullptr); // Store a camera handle for a clean-up @@ -1142,10 +1165,6 @@ TEST_P(EvsHidlTest, MultiCameraParameter) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Test each reported camera for (auto&& cam: cameraInfo) { bool isLogicalCam = false; @@ -1157,18 +1176,20 @@ TEST_P(EvsHidlTest, MultiCameraParameter) { continue; } + // Read a target resolution from the metadata + Stream targetCfg = + getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data())); + ASSERT_GT(targetCfg.width, 0); + ASSERT_GT(targetCfg.height, 0); + // Create two camera clients. - sp<IEvsCamera_1_1> pCamPrimary = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) - .withDefault(nullptr); + sp<IEvsCamera_1_1> pCamPrimary = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg); ASSERT_NE(pCamPrimary, nullptr); // Store a camera handle for a clean-up activeCameras.push_back(pCamPrimary); - sp<IEvsCamera_1_1> pCamSecondary = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) - .withDefault(nullptr); + sp<IEvsCamera_1_1> pCamSecondary = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg); ASSERT_NE(pCamSecondary, nullptr); // Store a camera handle for a clean-up @@ -1615,28 +1636,26 @@ TEST_P(EvsHidlTest, HighPriorityCameraClient) { // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Request exclusive access to the EVS display sp<IEvsDisplay_1_0> pDisplay = pEnumerator->openDisplay(); ASSERT_NE(pDisplay, nullptr); // Test each reported camera for (auto&& cam: cameraInfo) { + // Read a target resolution from the metadata + Stream targetCfg = + getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data())); + ASSERT_GT(targetCfg.width, 0); + ASSERT_GT(targetCfg.height, 0); + // Create two clients - sp<IEvsCamera_1_1> pCam0 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) - .withDefault(nullptr); + sp<IEvsCamera_1_1> pCam0 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg); ASSERT_NE(pCam0, nullptr); // Store a camera handle for a clean-up activeCameras.push_back(pCam0); - sp<IEvsCamera_1_1> pCam1 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) - .withDefault(nullptr); + sp<IEvsCamera_1_1> pCam1 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg); ASSERT_NE(pCam1, nullptr); // Store a camera handle for a clean-up @@ -2001,7 +2020,7 @@ TEST_P(EvsHidlTest, CameraUseStreamConfigToDisplay) { &streamCfgs)) { // Stream configurations are found in metadata RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32); - for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) { + for (unsigned offset = 0; offset < streamCfgs.count; offset += kStreamCfgSz) { if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT && ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) { @@ -2026,9 +2045,7 @@ TEST_P(EvsHidlTest, CameraUseStreamConfigToDisplay) { continue; } - sp<IEvsCamera_1_1> pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) - .withDefault(nullptr); + sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg); ASSERT_NE(pCam, nullptr); // Store a camera handle for a clean-up @@ -2106,7 +2123,7 @@ TEST_P(EvsHidlTest, MultiCameraStreamUseConfig) { &streamCfgs)) { // Stream configurations are found in metadata RawStreamConfig *ptr = reinterpret_cast<RawStreamConfig *>(streamCfgs.data.i32); - for (unsigned idx = 0; idx < streamCfgs.count; idx += kStreamCfgSz) { + for (unsigned offset = 0; offset < streamCfgs.count; offset += kStreamCfgSz) { if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT && ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) { @@ -2132,9 +2149,7 @@ TEST_P(EvsHidlTest, MultiCameraStreamUseConfig) { } // Create the first camera client with a selected stream configuration. - sp<IEvsCamera_1_1> pCam0 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) - .withDefault(nullptr); + sp<IEvsCamera_1_1> pCam0 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg); ASSERT_NE(pCam0, nullptr); // Store a camera handle for a clean-up @@ -2144,9 +2159,7 @@ TEST_P(EvsHidlTest, MultiCameraStreamUseConfig) { // configuration. int32_t id = targetCfg.id; targetCfg.id += 1; // EVS manager sees only the stream id. - sp<IEvsCamera_1_1> pCam1 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) - .withDefault(nullptr); + sp<IEvsCamera_1_1> pCam1 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg); ASSERT_EQ(pCam1, nullptr); // Store a camera handle for a clean-up @@ -2154,9 +2167,7 @@ TEST_P(EvsHidlTest, MultiCameraStreamUseConfig) { // Try again with same stream configuration. targetCfg.id = id; - pCam1 = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg)) - .withDefault(nullptr); + pCam1 = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg); ASSERT_NE(pCam1, nullptr); // Set up per-client frame receiver objects which will fire up its own thread @@ -2258,52 +2269,23 @@ TEST_P(EvsHidlTest, CameraStreamExternalBuffering) { LOG(INFO) << "Starting CameraStreamExternalBuffering test"; // Arbitrary constant (should be > 1 and not too big) - static const unsigned int kBuffersToHold = 6; + static const unsigned int kBuffersToHold = 3; // Get the camera list loadCameraList(); - // Using null stream configuration makes EVS uses the default resolution and - // output format. - Stream nullCfg = {}; - // Acquire the graphics buffer allocator android::GraphicBufferAllocator& alloc(android::GraphicBufferAllocator::get()); const auto usage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_OFTEN; - const auto format = HAL_PIXEL_FORMAT_RGBA_8888; - uint32_t width = 640; - uint32_t height = 360; - camera_metadata_entry_t streamCfgs; // Test each reported camera for (auto&& cam : cameraInfo) { - bool foundCfg = false; - if (!find_camera_metadata_entry(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()), - ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, - &streamCfgs)) { - // Stream configurations are found in metadata - RawStreamConfig* ptr = reinterpret_cast<RawStreamConfig*>(streamCfgs.data.i32); - - LOG(DEBUG) << __LINE__ << " start searching " << streamCfgs.count; - for (unsigned idx = 0; idx < streamCfgs.count; idx++) { - LOG(DEBUG) << "ptr->direction= " << ptr->direction - << " ptr->format= " << ptr->format; - if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT && - ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) { - width = ptr->width; - height = ptr->height; - foundCfg = true; - // Always use the 1st available configuration - break; - } - ++ptr; - } - } - - if (!foundCfg) { - LOG(INFO) << "No configuration found. Use default stream configurations."; - } + // Read a target resolution from the metadata + Stream targetCfg = + getFirstStreamConfiguration(reinterpret_cast<camera_metadata_t*>(cam.metadata.data())); + ASSERT_GT(targetCfg.width, 0); + ASSERT_GT(targetCfg.height, 0); // Allocate buffers to use hidl_vec<BufferDesc> buffers; @@ -2312,8 +2294,11 @@ TEST_P(EvsHidlTest, CameraStreamExternalBuffering) { unsigned pixelsPerLine; buffer_handle_t memHandle = nullptr; android::status_t result = - alloc.allocate(width, height, format, 1, usage, &memHandle, &pixelsPerLine, 0, - "CameraStreamExternalBufferingTest"); + alloc.allocate(targetCfg.width, targetCfg.height, + (android::PixelFormat)targetCfg.format, + /* layerCount = */ 1, usage, &memHandle, &pixelsPerLine, + /* graphicBufferId = */ 0, + /* requestorName = */ "CameraStreamExternalBufferingTest"); if (result != android::NO_ERROR) { LOG(ERROR) << __FUNCTION__ << " failed to allocate memory."; // Release previous allocated buffers @@ -2325,10 +2310,10 @@ TEST_P(EvsHidlTest, CameraStreamExternalBuffering) { BufferDesc buf; AHardwareBuffer_Desc* pDesc = reinterpret_cast<AHardwareBuffer_Desc*>(&buf.buffer.description); - pDesc->width = width; - pDesc->height = height; + pDesc->width = targetCfg.width; + pDesc->height = targetCfg.height; pDesc->layers = 1; - pDesc->format = format; + pDesc->format = static_cast<uint32_t>(targetCfg.format); pDesc->usage = usage; pDesc->stride = pixelsPerLine; buf.buffer.nativeHandle = memHandle; @@ -2340,9 +2325,7 @@ TEST_P(EvsHidlTest, CameraStreamExternalBuffering) { bool isLogicalCam = false; getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam); - sp<IEvsCamera_1_1> pCam = - IEvsCamera_1_1::castFrom(pEnumerator->openCamera_1_1(cam.v1.cameraId, nullCfg)) - .withDefault(nullptr); + sp<IEvsCamera_1_1> pCam = pEnumerator->openCamera_1_1(cam.v1.cameraId, targetCfg); ASSERT_NE(pCam, nullptr); // Store a camera handle for a clean-up @@ -2362,7 +2345,7 @@ TEST_P(EvsHidlTest, CameraStreamExternalBuffering) { } EXPECT_EQ(result, EvsResult::OK); - EXPECT_GE(delta, 0); + EXPECT_GE(delta, kBuffersToHold); // Set up a frame receiver object which will fire up its own thread. sp<FrameHandler> frameHandler = new FrameHandler(pCam, cam, @@ -2378,7 +2361,7 @@ TEST_P(EvsHidlTest, CameraStreamExternalBuffering) { sleep(1); // 1 second should be enough for at least 5 frames to be delivered worst case unsigned framesReceived = 0; frameHandler->getFramesCounters(&framesReceived, nullptr); - ASSERT_EQ(kBuffersToHold, framesReceived) << "Stream didn't stall at expected buffer limit"; + ASSERT_LE(kBuffersToHold, framesReceived) << "Stream didn't stall at expected buffer limit"; // Give back one buffer @@ -2387,9 +2370,10 @@ TEST_P(EvsHidlTest, CameraStreamExternalBuffering) { // Once we return a buffer, it shouldn't take more than 1/10 second to get a new one // filled since we require 10fps minimum -- but give a 10% allowance just in case. + unsigned framesReceivedAfter = 0; usleep(110 * kMillisecondsToMicroseconds); - frameHandler->getFramesCounters(&framesReceived, nullptr); - EXPECT_EQ(kBuffersToHold+1, framesReceived) << "Stream should've resumed"; + frameHandler->getFramesCounters(&framesReceivedAfter, nullptr); + EXPECT_EQ(framesReceived + 1, framesReceivedAfter) << "Stream should've resumed"; // Even when the camera pointer goes out of scope, the FrameHandler object will // keep the stream alive unless we tell it to shutdown. diff --git a/automotive/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp b/automotive/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp index 583a455160..58423c8187 100644 --- a/automotive/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp +++ b/automotive/evs/common/utils/default/test/fuzz/FormatConvertFuzzer.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <fuzzer/FuzzedDataProvider.h> #include <cmath> #include <cstdlib> #include <cstring> @@ -21,36 +22,43 @@ #include "FormatConvert.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, std::size_t size) { - if (size < 256) { + // 1 random value (4bytes) + min imagesize = 16*2 times bytes per pixel (worse case 2) + if (size < (4 + 16 * 2 * 2)) { return 0; } + FuzzedDataProvider fdp(data, size); + std::size_t image_pixel_size = size - 4; + image_pixel_size = (image_pixel_size & INT_MAX) / 2; - std::srand(std::time(nullptr)); // use current time as seed for random generator - int random_variable = std::rand() % 10; - int width = (int)sqrt(size); - int height = width * ((float)random_variable / 10.0); + // API have a requirement that width must be divied by 16 except yuyvtorgb + int min_height = 2; + int max_height = (image_pixel_size / 16) & ~(1); // must be even number + int height = fdp.ConsumeIntegralInRange<uint32_t>(min_height, max_height); + int width = (image_pixel_size / height) & ~(16); // must be divisible by 16 - uint8_t* src = (uint8_t*)malloc(sizeof(uint8_t) * size); - memcpy(src, data, sizeof(uint8_t) * (size)); - uint32_t* tgt = (uint32_t*)malloc(sizeof(uint32_t) * size); + uint8_t* src = (uint8_t*)(data + 4); + uint32_t* tgt = (uint32_t*)malloc(sizeof(uint32_t) * image_pixel_size); #ifdef COPY_NV21_TO_RGB32 - android::hardware::automotive::evs::common::Utils::copyNV21toRGB32(width, height, src, tgt, 0); + android::hardware::automotive::evs::common::Utils::copyNV21toRGB32(width, height, src, tgt, + width); #elif COPY_NV21_TO_BGR32 - android::hardware::automotive::evs::common::Utils::copyNV21toBGR32(width, height, src, tgt, 0); + android::hardware::automotive::evs::common::Utils::copyNV21toBGR32(width, height, src, tgt, + width); #elif COPY_YV12_TO_RGB32 - android::hardware::automotive::evs::common::Utils::copyYV12toRGB32(width, height, src, tgt, 0); + android::hardware::automotive::evs::common::Utils::copyYV12toRGB32(width, height, src, tgt, + width); #elif COPY_YV12_TO_BGR32 - android::hardware::automotive::evs::common::Utils::copyYV12toBGR32(width, height, src, tgt, 0); + android::hardware::automotive::evs::common::Utils::copyYV12toBGR32(width, height, src, tgt, + width); #elif COPY_YUYV_TO_RGB32 - android::hardware::automotive::evs::common::Utils::copyYUYVtoRGB32(width, height, src, 0, tgt, - 0); + android::hardware::automotive::evs::common::Utils::copyYUYVtoRGB32(width, height, src, width, + tgt, width); #elif COPY_YUYV_TO_BGR32 - android::hardware::automotive::evs::common::Utils::copyYUYVtoBGR32(width, height, src, 0, tgt, - 0); + android::hardware::automotive::evs::common::Utils::copyYUYVtoBGR32(width, height, src, width, + tgt, width); #endif - free(src); free(tgt); return 0; diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp index ffa0c13958..0b49ef9d2c 100644 --- a/automotive/vehicle/2.0/default/Android.bp +++ b/automotive/vehicle/2.0/default/Android.bp @@ -182,6 +182,7 @@ cc_test { ], shared_libs: [ "libbase", + "libcutils", ], header_libs: ["libbase_headers"], test_suites: ["general-tests"], diff --git a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc index c8c89dc821..44f9134714 100644 --- a/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc +++ b/automotive/vehicle/2.0/default/android.hardware.automotive.vehicle@2.0-service.rc @@ -1,4 +1,4 @@ service vendor.vehicle-hal-2.0 /vendor/bin/hw/android.hardware.automotive.vehicle@2.0-service - class hal + class early_hal user vehicle_network group system inet diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h index fcfe7612ac..6706258717 100644 --- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h +++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleHalManager.h @@ -76,6 +76,9 @@ public: Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& options) override; private: + // Set unit test class as friend class to test private functions. + friend class VehicleHalManagerTestHelper; + using VehiclePropValuePtr = VehicleHal::VehiclePropValuePtr; // Returns true if needs to call again shortly. using RetriableAction = std::function<bool()>; @@ -105,14 +108,20 @@ public: void cmdDumpOneProperty(int fd, int32_t prop, int32_t areaId); void cmdDumpOneProperty(int fd, int rowNumber, const VehiclePropConfig& config); + bool cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options); + static bool checkArgumentsSize(int fd, const hidl_vec<hidl_string>& options, size_t minSize); static bool checkCallerHasWritePermissions(int fd); - static bool safelyParseInt(int fd, int index, std::string s, int* out); + template <typename T> + static bool safelyParseInt(int fd, int index, const std::string& s, T* out); + static bool safelyParseFloat(int fd, int index, const std::string& s, float* out); + // Parses "s" as a hex string and populate "*bytes". The hex string must be in the format of + // valid hex format, e.g. "0xABCD". + static bool parseHexString(int fd, const std::string& s, std::vector<uint8_t>* bytes); void cmdHelp(int fd) const; void cmdListAllProperties(int fd) const; void cmdDumpAllProperties(int fd); void cmdDumpSpecificProperties(int fd, const hidl_vec<hidl_string>& options); - void cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options); static bool isSubscribable(const VehiclePropConfig& config, SubscribeFlags flags); @@ -120,7 +129,18 @@ public: static float checkSampleRate(const VehiclePropConfig& config, float sampleRate); static ClientId getClientId(const sp<IVehicleCallback>& callback); -private: + + // Parses the cmdline options for "--set" command. "*prop" would be populated with the + // the properties to be set. Returns true when the cmdline options are valid, false otherwise. + static bool parseSetPropOptions(int fd, const hidl_vec<hidl_string>& options, + VehiclePropValue* prop); + // Parses the options and get the values for the current option specified by "*index". "*index" + // would advance to the next option field (e.g., the next "-f"). Returns a list of values for + // the current option. + static std::vector<std::string> getOptionValues(const hidl_vec<hidl_string>& options, + size_t* index); + + private: VehicleHal* mHal; std::unique_ptr<VehiclePropConfigIndex> mConfigIndex; SubscriptionManager mSubscriptionManager; diff --git a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp index dc5d3d300e..e34e692bfc 100644 --- a/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp +++ b/automotive/vehicle/2.0/default/common/src/VehicleHalManager.cpp @@ -20,7 +20,9 @@ #include <cmath> #include <fstream> +#include <unordered_set> +#include <android-base/parsedouble.h> #include <android-base/parseint.h> #include <android-base/strings.h> #include <android/hardware/automotive/vehicle/2.0/BpHwVehicleCallback.h> @@ -44,15 +46,34 @@ using ::android::base::EqualsIgnoreCase; using ::android::hardware::hidl_handle; using ::android::hardware::hidl_string; +namespace { + constexpr std::chrono::milliseconds kHalEventBatchingTimeWindow(10); const VehiclePropValue kEmptyValue{}; +// A list of supported options for "--set" command. +const std::unordered_set<std::string> kSetPropOptions = { + // integer. + "-i", + // 64bit integer. + "-i64", + // float. + "-f", + // string. + "-s", + // bytes in hex format, e.g. 0xDEADBEEF. + "-b", + // Area id in integer. + "-a"}; + +} // namespace + /** * Indicates what's the maximum size of hidl_vec<VehiclePropValue> we want * to store in reusable object pool. */ -constexpr auto kMaxHidlVecOfVehiclPropValuePoolSize = 20; +constexpr auto kMaxHidlVecOfVehiclePropValuePoolSize = 20; Return<void> VehicleHalManager::getAllPropConfigs(getAllPropConfigs_cb _hidl_cb) { ALOGI("getAllPropConfigs called"); @@ -213,6 +234,11 @@ void VehicleHalManager::cmdDump(int fd, const hidl_vec<hidl_string>& options) { } else if (EqualsIgnoreCase(option, "--get")) { cmdDumpSpecificProperties(fd, options); } else if (EqualsIgnoreCase(option, "--set")) { + if (!checkCallerHasWritePermissions(fd)) { + dprintf(fd, "Caller does not have write permission\n"); + return; + } + // Ignore the return value for this. cmdSetOneProperty(fd, options); } else { dprintf(fd, "Invalid option: %s\n", option.c_str()); @@ -239,7 +265,8 @@ bool VehicleHalManager::checkArgumentsSize(int fd, const hidl_vec<hidl_string>& return false; } -bool VehicleHalManager::safelyParseInt(int fd, int index, std::string s, int* out) { +template <typename T> +bool VehicleHalManager::safelyParseInt(int fd, int index, const std::string& s, T* out) { if (!android::base::ParseInt(s, out)) { dprintf(fd, "non-integer argument at index %d: %s\n", index, s.c_str()); return false; @@ -247,19 +274,27 @@ bool VehicleHalManager::safelyParseInt(int fd, int index, std::string s, int* ou return true; } +bool VehicleHalManager::safelyParseFloat(int fd, int index, const std::string& s, float* out) { + if (!android::base::ParseFloat(s, out)) { + dprintf(fd, "non-float argument at index %d: %s\n", index, s.c_str()); + return false; + } + return true; +} + void VehicleHalManager::cmdHelp(int fd) const { dprintf(fd, "Usage: \n\n"); dprintf(fd, "[no args]: dumps (id and value) all supported properties \n"); dprintf(fd, "--help: shows this help\n"); dprintf(fd, "--list: lists the ids of all supported properties\n"); dprintf(fd, "--get <PROP1> [PROP2] [PROPN]: dumps the value of specific properties \n"); - // TODO: support other formats (int64, float, bytes) dprintf(fd, - "--set <PROP> <i|s> <VALUE_1> [<i|s> <VALUE_N>] [a AREA_ID] : sets the value of " - "property PROP, using arbitrary number of key/value parameters (i for int32, " - "s for string) and an optional area.\n" - "Notice that the string value can be set just once, while the other can have multiple " - "values (so they're used in the respective array)\n"); + "--set <PROP> [-i INT_VALUE [INT_VALUE ...]] [-i64 INT64_VALUE [INT64_VALUE ...]] " + "[-f FLOAT_VALUE [FLOAT_VALUE ...]] [-s STR_VALUE] " + "[-b BYTES_VALUE] [-a AREA_ID] : sets the value of property PROP. " + "Notice that the string, bytes and area value can be set just once, while the other can" + " have multiple values (so they're used in the respective array), " + "BYTES_VALUE is in the form of 0xXXXX, e.g. 0xdeadbeef.\n"); } void VehicleHalManager::cmdListAllProperties(int fd) const { @@ -337,102 +372,49 @@ void VehicleHalManager::cmdDumpOneProperty(int fd, int32_t prop, int32_t areaId) VehiclePropValue input; input.prop = prop; input.areaId = areaId; - auto callback = [&](StatusCode status, const VehiclePropValue& output) { + auto callback = [&fd, &prop](StatusCode status, const VehiclePropValue& output) { if (status == StatusCode::OK) { dprintf(fd, "%s\n", toString(output).c_str()); } else { dprintf(fd, "Could not get property %d. Error: %s\n", prop, toString(status).c_str()); } }; - get(input, callback); -} - -void VehicleHalManager::cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options) { - if (!checkCallerHasWritePermissions(fd) || !checkArgumentsSize(fd, options, 3)) return; - size_t size = options.size(); + StatusCode status; + auto value = mHal->get(input, &status); + callback(status, value.get() ? *value : kEmptyValue); +} - // Syntax is --set PROP Type1 Value1 TypeN ValueN, so number of arguments must be even - if (size % 2 != 0) { - dprintf(fd, "must pass even number of arguments (passed %zu)\n", size); - return; +bool VehicleHalManager::cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options) { + if (!checkArgumentsSize(fd, options, 4)) { + dprintf(fd, "Requires at least 4 options, see help\n"); + return false; } - int numberValues = (size - 2) / 2; - - VehiclePropValue prop; - if (!safelyParseInt(fd, 1, options[1], &prop.prop)) return; - prop.timestamp = elapsedRealtimeNano(); - prop.status = VehiclePropertyStatus::AVAILABLE; - - // First pass: calculate sizes - int sizeInt32 = 0; - int stringIndex = 0; - int areaIndex = 0; - for (int i = 2, kv = 1; kv <= numberValues; kv++) { - // iterate through the kv=1..n key/value pairs, accessing indexes i / i+1 at each step - std::string type = options[i]; - std::string value = options[i + 1]; - if (EqualsIgnoreCase(type, "i")) { - sizeInt32++; - } else if (EqualsIgnoreCase(type, "s")) { - if (stringIndex != 0) { - dprintf(fd, - "defining string value (%s) again at index %d (already defined at %d=%s" - ")\n", - value.c_str(), i, stringIndex, options[stringIndex + 1].c_str()); - return; - } - stringIndex = i; - } else if (EqualsIgnoreCase(type, "a")) { - if (areaIndex != 0) { - dprintf(fd, - "defining area value (%s) again at index %d (already defined at %d=%s" - ")\n", - value.c_str(), i, areaIndex, options[areaIndex + 1].c_str()); - return; - } - areaIndex = i; - } else { - dprintf(fd, "invalid (%s) type at index %d\n", type.c_str(), i); - return; - } - i += 2; - } - prop.value.int32Values.resize(sizeInt32); - - // Second pass: populate it - int indexInt32 = 0; - for (int i = 2, kv = 1; kv <= numberValues; kv++) { - // iterate through the kv=1..n key/value pairs, accessing indexes i / i+1 at each step - int valueIndex = i + 1; - std::string type = options[i]; - std::string value = options[valueIndex]; - if (EqualsIgnoreCase(type, "i")) { - int safeInt; - if (!safelyParseInt(fd, valueIndex, value, &safeInt)) return; - prop.value.int32Values[indexInt32++] = safeInt; - } else if (EqualsIgnoreCase(type, "s")) { - prop.value.stringValue = value; - } else if (EqualsIgnoreCase(type, "a")) { - if (!safelyParseInt(fd, valueIndex, value, &prop.areaId)) return; - } - i += 2; + + VehiclePropValue prop = {}; + if (!parseSetPropOptions(fd, options, &prop)) { + return false; } ALOGD("Setting prop %s", toString(prop).c_str()); - auto status = set(prop); + + // Do not use VehicleHalManager::set here because we don't want to check write permission. + // Caller should be able to use the debug interface to set read-only properties. + handlePropertySetEvent(prop); + auto status = mHal->set(prop); + if (status == StatusCode::OK) { dprintf(fd, "Set property %s\n", toString(prop).c_str()); - } else { - dprintf(fd, "Failed to set property %s: %s\n", toString(prop).c_str(), - toString(status).c_str()); + return true; } + dprintf(fd, "Failed to set property %s: %s\n", toString(prop).c_str(), + toString(status).c_str()); + return false; } void VehicleHalManager::init() { ALOGI("VehicleHalManager::init"); - mHidlVecOfVehiclePropValuePool.resize(kMaxHidlVecOfVehiclPropValuePoolSize); - + mHidlVecOfVehiclePropValuePool.resize(kMaxHidlVecOfVehiclePropValuePoolSize); mBatchingConsumer.run(&mEventQueue, kHalEventBatchingTimeWindow, @@ -486,7 +468,7 @@ void VehicleHalManager::onBatchHalEvent(const std::vector<VehiclePropValuePtr>& for (const HalClientValues& cv : clientValues) { auto vecSize = cv.values.size(); hidl_vec<VehiclePropValue> vec; - if (vecSize < kMaxHidlVecOfVehiclPropValuePoolSize) { + if (vecSize < kMaxHidlVecOfVehiclePropValuePoolSize) { vec.setToExternal(&mHidlVecOfVehiclePropValuePool[0], vecSize); } else { vec.resize(vecSize); @@ -595,6 +577,158 @@ ClientId VehicleHalManager::getClientId(const sp<IVehicleCallback>& callback) { } } +std::vector<std::string> VehicleHalManager::getOptionValues(const hidl_vec<hidl_string>& options, + size_t* index) { + std::vector<std::string> values; + while (*index < options.size()) { + std::string option = options[*index]; + if (kSetPropOptions.find(option) != kSetPropOptions.end()) { + return std::move(values); + } + values.push_back(option); + (*index)++; + } + return std::move(values); +} + +bool VehicleHalManager::parseSetPropOptions(int fd, const hidl_vec<hidl_string>& options, + VehiclePropValue* prop) { + // Options format: + // --set PROP [-f f1 f2...] [-i i1 i2...] [-i64 i1 i2...] [-s s1 s2...] [-b b1 b2...] [-a a] + size_t optionIndex = 1; + int propValue; + if (!safelyParseInt(fd, optionIndex, options[optionIndex], &propValue)) { + dprintf(fd, "property value: \"%s\" is not a valid int\n", options[optionIndex].c_str()); + return false; + } + prop->prop = propValue; + prop->timestamp = elapsedRealtimeNano(); + prop->status = VehiclePropertyStatus::AVAILABLE; + optionIndex++; + std::unordered_set<std::string> parsedOptions; + + while (optionIndex < options.size()) { + std::string type = options[optionIndex]; + optionIndex++; + size_t currentIndex = optionIndex; + std::vector<std::string> values = getOptionValues(options, &optionIndex); + if (parsedOptions.find(type) != parsedOptions.end()) { + dprintf(fd, "duplicate \"%s\" options\n", type.c_str()); + return false; + } + parsedOptions.insert(type); + if (EqualsIgnoreCase(type, "-i")) { + if (values.size() == 0) { + dprintf(fd, "no values specified when using \"-i\"\n"); + return false; + } + prop->value.int32Values.resize(values.size()); + for (size_t i = 0; i < values.size(); i++) { + int32_t safeInt; + if (!safelyParseInt(fd, currentIndex + i, values[i], &safeInt)) { + dprintf(fd, "value: \"%s\" is not a valid int\n", values[i].c_str()); + return false; + } + prop->value.int32Values[i] = safeInt; + } + } else if (EqualsIgnoreCase(type, "-i64")) { + if (values.size() == 0) { + dprintf(fd, "no values specified when using \"-i64\"\n"); + return false; + } + prop->value.int64Values.resize(values.size()); + for (size_t i = 0; i < values.size(); i++) { + int64_t safeInt; + if (!safelyParseInt(fd, currentIndex + i, values[i], &safeInt)) { + dprintf(fd, "value: \"%s\" is not a valid int64\n", values[i].c_str()); + return false; + } + prop->value.int64Values[i] = safeInt; + } + } else if (EqualsIgnoreCase(type, "-f")) { + if (values.size() == 0) { + dprintf(fd, "no values specified when using \"-f\"\n"); + return false; + } + prop->value.floatValues.resize(values.size()); + for (size_t i = 0; i < values.size(); i++) { + float safeFloat; + if (!safelyParseFloat(fd, currentIndex + i, values[i], &safeFloat)) { + dprintf(fd, "value: \"%s\" is not a valid float\n", values[i].c_str()); + return false; + } + prop->value.floatValues[i] = safeFloat; + } + } else if (EqualsIgnoreCase(type, "-s")) { + if (values.size() != 1) { + dprintf(fd, "expect exact one value when using \"-s\"\n"); + return false; + } + prop->value.stringValue = values[0]; + } else if (EqualsIgnoreCase(type, "-b")) { + if (values.size() != 1) { + dprintf(fd, "expect exact one value when using \"-b\"\n"); + return false; + } + std::vector<uint8_t> bytes; + if (!parseHexString(fd, values[0], &bytes)) { + dprintf(fd, "value: \"%s\" is not a valid hex string\n", values[0].c_str()); + return false; + } + prop->value.bytes = bytes; + } else if (EqualsIgnoreCase(type, "-a")) { + if (values.size() != 1) { + dprintf(fd, "expect exact one value when using \"-a\"\n"); + return false; + } + if (!safelyParseInt(fd, currentIndex, values[0], &(prop->areaId))) { + dprintf(fd, "area ID: \"%s\" is not a valid int\n", values[0].c_str()); + return false; + } + } else { + dprintf(fd, "unknown option: %s\n", type.c_str()); + return false; + } + } + + return true; +} + +bool VehicleHalManager::parseHexString(int fd, const std::string& s, std::vector<uint8_t>* bytes) { + if (s.size() % 2 != 0) { + dprintf(fd, "invalid hex string: %s, should have even size\n", s.c_str()); + return false; + } + if (strncmp(s.substr(0, 2).c_str(), "0x", 2)) { + dprintf(fd, "hex string should start with \"0x\", got %s\n", s.c_str()); + return false; + } + std::string subs = s.substr(2); + std::transform(subs.begin(), subs.end(), subs.begin(), + [](unsigned char c) { return std::tolower(c); }); + + bool highDigit = true; + for (size_t i = 0; i < subs.size(); i++) { + char c = subs[i]; + uint8_t v; + if (c >= '0' && c <= '9') { + v = c - '0'; + } else if (c >= 'a' && c <= 'f') { + v = c - 'a' + 10; + } else { + dprintf(fd, "invalid character %c in hex string %s\n", c, subs.c_str()); + return false; + } + if (highDigit) { + (*bytes).push_back(v * 16); + } else { + (*bytes)[bytes->size() - 1] += v; + } + highDigit = !highDigit; + } + return true; +} + } // namespace V2_0 } // namespace vehicle } // namespace automotive diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h index 8ff492471d..55617be30d 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h @@ -307,6 +307,18 @@ const ConfigDeclaration kVehicleProperties[]{ .prop = toInt(VehicleProperty::CRITICALLY_LOW_TIRE_PRESSURE), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::STATIC, + .areaConfigs = {VehicleAreaConfig{ + .areaId = WHEEL_FRONT_LEFT, + }, + VehicleAreaConfig{ + .areaId = WHEEL_FRONT_RIGHT, + }, + VehicleAreaConfig{ + .areaId = WHEEL_REAR_LEFT, + }, + VehicleAreaConfig{ + .areaId = WHEEL_REAR_RIGHT, + }}, }, .initialAreaValues = {{WHEEL_FRONT_LEFT, {.floatValues = {137.0f}}}, {WHEEL_FRONT_RIGHT, {.floatValues = {137.0f}}}, @@ -1032,14 +1044,6 @@ const ConfigDeclaration kVehicleProperties[]{ { .config = { - .prop = toInt(VehicleProperty::STORAGE_ENCRYPTION_BINDING_SEED), - .access = VehiclePropertyAccess::READ_WRITE, - .changeMode = VehiclePropertyChangeMode::ON_CHANGE, - }, - }, - { - .config = - { .prop = toInt(VehicleProperty::WATCHDOG_ALIVE), .access = VehiclePropertyAccess::WRITE, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, @@ -1105,6 +1109,42 @@ const ConfigDeclaration kVehicleProperties[]{ .changeMode = VehiclePropertyChangeMode::ON_CHANGE, }, }, + { + .config = + { + .prop = PLACEHOLDER_PROPERTY_INT, + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {0}}, + }, + { + .config = + { + .prop = PLACEHOLDER_PROPERTY_FLOAT, + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.floatValues = {0.0f}}, + }, + { + .config = + { + .prop = PLACEHOLDER_PROPERTY_BOOLEAN, + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.int32Values = {0 /* false */}}, + }, + { + .config = + { + .prop = PLACEHOLDER_PROPERTY_STRING, + .access = VehiclePropertyAccess::READ_WRITE, + .changeMode = VehiclePropertyChangeMode::ON_CHANGE, + }, + .initialValue = {.stringValue = {"Test"}}, + }, #ifdef ENABLE_VENDOR_CLUSTER_PROPERTY_FOR_TESTING // Vendor propetry for E2E ClusterHomeService testing. { diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PropertyUtils.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PropertyUtils.h index d5f6a1841e..51251a7e70 100644 --- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/PropertyUtils.h +++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/PropertyUtils.h @@ -189,6 +189,19 @@ enum class FakeDataCommand : int32_t { KeyPress = 100, }; +/** + * These properties are placeholder properties for developers to test new features without + * implementing a real property. + */ +constexpr int32_t PLACEHOLDER_PROPERTY_INT = + 0x2a11 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::INT32; +constexpr int32_t PLACEHOLDER_PROPERTY_FLOAT = + 0x2a11 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::FLOAT; +constexpr int32_t PLACEHOLDER_PROPERTY_BOOLEAN = + 0x2a11 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::BOOLEAN; +constexpr int32_t PLACEHOLDER_PROPERTY_STRING = + 0x2a11 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::STRING; + const int32_t kHvacPowerProperties[] = { toInt(VehicleProperty::HVAC_FAN_SPEED), toInt(VehicleProperty::HVAC_FAN_DIRECTION), diff --git a/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp b/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp index 09750718a0..bdf46fb24c 100644 --- a/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp +++ b/automotive/vehicle/2.0/default/tests/VehicleHalManager_test.cpp @@ -18,6 +18,7 @@ #include <iostream> #include <android-base/macros.h> +#include <cutils/native_handle.h> #include <utils/SystemClock.h> #include <gtest/gtest.h> @@ -32,6 +33,18 @@ namespace automotive { namespace vehicle { namespace V2_0 { +// A simple helper class to expose 'cmdSetOneProperty' to the unit tests. +class VehicleHalManagerTestHelper { + public: + VehicleHalManagerTestHelper(VehicleHalManager* manager) { mManager = manager; } + bool cmdSetOneProperty(int fd, const hidl_vec<hidl_string>& options) { + return mManager->cmdSetOneProperty(fd, options); + } + + public: + VehicleHalManager* mManager; +}; + namespace { using namespace std::placeholders; @@ -57,33 +70,21 @@ public: auto property = static_cast<VehicleProperty>(requestedPropValue.prop); int32_t areaId = requestedPropValue.areaId; - switch (property) { - case VehicleProperty::INFO_MAKE: - pValue = getValuePool()->obtainString(kCarMake); - break; - case VehicleProperty::INFO_FUEL_CAPACITY: - if (fuelCapacityAttemptsLeft-- > 0) { - // Emulate property not ready yet. - *outStatus = StatusCode::TRY_AGAIN; - } else { - pValue = getValuePool()->obtainFloat(42.42); - } - break; - default: - if (requestedPropValue.prop == kCustomComplexProperty) { - pValue = getValuePool()->obtainComplex(); - pValue->value.int32Values = hidl_vec<int32_t> { 10, 20 }; - pValue->value.int64Values = hidl_vec<int64_t> { 30, 40 }; - pValue->value.floatValues = hidl_vec<float_t> { 1.1, 2.2 }; - pValue->value.bytes = hidl_vec<uint8_t> { 1, 2, 3 }; - pValue->value.stringValue = kCarMake; - break; - } - auto key = makeKey(toInt(property), areaId); - if (mValues.count(key) == 0) { - ALOGW(""); - } - pValue = getValuePool()->obtain(mValues[key]); + if (property == VehicleProperty::INFO_FUEL_CAPACITY) { + if (fuelCapacityAttemptsLeft-- > 0) { + // Emulate property not ready yet. + *outStatus = StatusCode::TRY_AGAIN; + } else { + pValue = getValuePool()->obtainFloat(42.42); + } + } else { + auto key = makeKey(requestedPropValue); + if (mValues.count(key) == 0) { + ALOGW("key not found\n"); + *outStatus = StatusCode::INVALID_ARG; + return pValue; + } + pValue = getValuePool()->obtain(mValues[key]); } if (*outStatus == StatusCode::OK && pValue.get() != nullptr) { @@ -100,7 +101,6 @@ public: && mirrorFoldAttemptsLeft-- > 0) { return StatusCode::TRY_AGAIN; } - mValues[makeKey(propValue)] = propValue; return StatusCode::OK; } @@ -181,6 +181,18 @@ public: actualStatusCode = refStatus; } + MockedVehicleHal::VehiclePropValuePtr getComplexProperty() { + auto pValue = objectPool->obtainComplex(); + pValue->prop = kCustomComplexProperty; + pValue->areaId = 0; + pValue->value.int32Values = hidl_vec<int32_t>{10, 20}; + pValue->value.int64Values = hidl_vec<int64_t>{30, 40}; + pValue->value.floatValues = hidl_vec<float_t>{1.1, 2.2}; + pValue->value.bytes = hidl_vec<uint8_t>{1, 2, 3}; + pValue->value.stringValue = kCarMake; + return pValue; + } + public: VehiclePropValue actualValue; StatusCode actualStatusCode; @@ -308,6 +320,8 @@ TEST_F(VehicleHalManagerTest, subscribe_WriteOnly) { } TEST_F(VehicleHalManagerTest, get_Complex) { + ASSERT_EQ(StatusCode::OK, hal->set(*getComplexProperty().get())); + invokeGet(kCustomComplexProperty, 0); ASSERT_EQ(StatusCode::OK, actualStatusCode); @@ -334,6 +348,11 @@ TEST_F(VehicleHalManagerTest, get_Complex) { } TEST_F(VehicleHalManagerTest, get_StaticString) { + auto pValue = objectPool->obtainString(kCarMake); + pValue->prop = toInt(VehicleProperty::INFO_MAKE); + pValue->areaId = 0; + ASSERT_EQ(StatusCode::OK, hal->set(*pValue.get())); + invokeGet(toInt(VehicleProperty::INFO_MAKE), 0); ASSERT_EQ(StatusCode::OK, actualStatusCode); @@ -458,6 +477,138 @@ TEST(HalClientVectorTest, basic) { ASSERT_TRUE(clients.isEmpty()); } +TEST_F(VehicleHalManagerTest, debug) { + hidl_handle fd = {}; + fd.setTo(native_handle_create(/*numFds=*/1, /*numInts=*/0), /*shouldOwn=*/true); + + // Because debug function returns void, so no way to check return value. + manager->debug(fd, {}); + manager->debug(fd, {"--help"}); + manager->debug(fd, {"--list"}); + manager->debug(fd, {"--get"}); + manager->debug(fd, {"--set"}); + manager->debug(fd, {"invalid"}); +} + +struct SetPropTestCase { + std::string test_name; + const hidl_vec<hidl_string> configs; + bool success; +}; + +class VehicleHalManagerSetPropTest : public VehicleHalManagerTest, + public testing::WithParamInterface<SetPropTestCase> {}; + +TEST_P(VehicleHalManagerSetPropTest, cmdSetOneProperty) { + const SetPropTestCase& tc = GetParam(); + VehicleHalManagerTestHelper helper(manager.get()); + ASSERT_EQ(tc.success, helper.cmdSetOneProperty(STDERR_FILENO, tc.configs)); +} + +std::vector<SetPropTestCase> GenSetPropParams() { + char infoMakeProperty[100] = {}; + snprintf(infoMakeProperty, sizeof(infoMakeProperty), "%d", toInt(VehicleProperty::INFO_MAKE)); + return { + {"success_set_string", {"--set", infoMakeProperty, "-s", kCarMake}, true}, + {"success_set_bytes", {"--set", infoMakeProperty, "-b", "0xdeadbeef"}, true}, + {"success_set_bytes_caps", {"--set", infoMakeProperty, "-b", "0xDEADBEEF"}, true}, + {"success_set_int", {"--set", infoMakeProperty, "-i", "2147483647"}, true}, + {"success_set_ints", + {"--set", infoMakeProperty, "-i", "2147483647", "0", "-2147483648"}, + true}, + {"success_set_int64", + {"--set", infoMakeProperty, "-i64", "-9223372036854775808"}, + true}, + {"success_set_int64s", + {"--set", infoMakeProperty, "-i64", "-9223372036854775808", "0", + "9223372036854775807"}, + true}, + {"success_set_float", {"--set", infoMakeProperty, "-f", "1.175494351E-38"}, true}, + {"success_set_floats", + {"--set", infoMakeProperty, "-f", "-3.402823466E+38", "0", "3.402823466E+38"}, + true}, + {"success_set_area", {"--set", infoMakeProperty, "-a", "2147483647"}, true}, + {"fail_no_options", {}, false}, + {"fail_less_than_4_options", {"--set", infoMakeProperty, "-i"}, false}, + {"fail_unknown_options", {"--set", infoMakeProperty, "-s", kCarMake, "-abcd"}, false}, + {"fail_invalid_property", {"--set", "not valid", "-s", kCarMake}, false}, + {"fail_duplicate_string", + {"--set", infoMakeProperty, "-s", kCarMake, "-s", kCarMake}, + false}, + {"fail_multiple_strings", {"--set", infoMakeProperty, "-s", kCarMake, kCarMake}, false}, + {"fail_no_string_value", {"--set", infoMakeProperty, "-s", "-a", "1234"}, false}, + {"fail_duplicate_bytes", + {"--set", infoMakeProperty, "-b", "0xdeadbeef", "-b", "0xdeadbeef"}, + false}, + {"fail_multiple_bytes", + {"--set", infoMakeProperty, "-b", "0xdeadbeef", "0xdeadbeef"}, + false}, + {"fail_invalid_bytes", {"--set", infoMakeProperty, "-b", "0xgood"}, false}, + {"fail_invalid_bytes_no_prefix", {"--set", infoMakeProperty, "-b", "deadbeef"}, false}, + {"fail_invalid_int", {"--set", infoMakeProperty, "-i", "abc"}, false}, + {"fail_int_out_of_range", {"--set", infoMakeProperty, "-i", "2147483648"}, false}, + {"fail_no_int_value", {"--set", infoMakeProperty, "-i", "-s", kCarMake}, false}, + {"fail_invalid_int64", {"--set", infoMakeProperty, "-i64", "abc"}, false}, + {"fail_int64_out_of_range", + {"--set", infoMakeProperty, "-i64", "-9223372036854775809"}, + false}, + {"fail_no_int64_value", {"--set", infoMakeProperty, "-i64", "-s", kCarMake}, false}, + {"fail_invalid_float", {"--set", infoMakeProperty, "-f", "abc"}, false}, + {"fail_float_out_of_range", + {"--set", infoMakeProperty, "-f", "-3.402823466E+39"}, + false}, + {"fail_no_float_value", {"--set", infoMakeProperty, "-f", "-s", kCarMake}, false}, + {"fail_multiple_areas", {"--set", infoMakeProperty, "-a", "2147483648", "0"}, false}, + {"fail_invalid_area", {"--set", infoMakeProperty, "-a", "abc"}, false}, + {"fail_area_out_of_range", {"--set", infoMakeProperty, "-a", "2147483648"}, false}, + {"fail_no_area_value", {"--set", infoMakeProperty, "-a", "-s", kCarMake}, false}, + }; +} + +INSTANTIATE_TEST_SUITE_P( + VehicleHalManagerSetPropTests, VehicleHalManagerSetPropTest, + testing::ValuesIn(GenSetPropParams()), + [](const testing::TestParamInfo<VehicleHalManagerSetPropTest::ParamType>& info) { + return info.param.test_name; + }); + +TEST_F(VehicleHalManagerTest, SetComplexPropTest) { + char infoMakeProperty[100] = {}; + snprintf(infoMakeProperty, sizeof(infoMakeProperty), "%d", toInt(VehicleProperty::INFO_MAKE)); + VehicleHalManagerTestHelper helper(manager.get()); + ASSERT_TRUE(helper.cmdSetOneProperty( + STDERR_FILENO, {"--set", infoMakeProperty, "-s", kCarMake, + "-b", "0xdeadbeef", "-i", "2147483647", + "0", "-2147483648", "-i64", "-9223372036854775808", + "0", "9223372036854775807", "-f", "-3.402823466E+38", + "0", "3.402823466E+38", "-a", "123"})); + StatusCode status = StatusCode::OK; + VehiclePropValue requestProp; + requestProp.prop = toInt(VehicleProperty::INFO_MAKE); + requestProp.areaId = 123; + auto value = hal->get(requestProp, &status); + ASSERT_EQ(StatusCode::OK, status); + ASSERT_EQ(value->prop, toInt(VehicleProperty::INFO_MAKE)); + ASSERT_EQ(value->areaId, 123); + ASSERT_STREQ(kCarMake, value->value.stringValue.c_str()); + uint8_t bytes[] = {0xde, 0xad, 0xbe, 0xef}; + ASSERT_FALSE(memcmp(bytes, value->value.bytes.data(), sizeof(bytes))); + ASSERT_EQ(3u, value->value.int32Values.size()); + ASSERT_EQ(2147483647, value->value.int32Values[0]); + ASSERT_EQ(0, value->value.int32Values[1]); + ASSERT_EQ(-2147483648, value->value.int32Values[2]); + ASSERT_EQ(3u, value->value.int64Values.size()); + // -9223372036854775808 is not a valid literal since '-' and '9223372036854775808' would be two + // tokens and the later does not fit in unsigned long long. + ASSERT_EQ(-9223372036854775807 - 1, value->value.int64Values[0]); + ASSERT_EQ(0, value->value.int64Values[1]); + ASSERT_EQ(9223372036854775807, value->value.int64Values[2]); + ASSERT_EQ(3u, value->value.floatValues.size()); + ASSERT_EQ(-3.402823466E+38f, value->value.floatValues[0]); + ASSERT_EQ(0.0f, value->value.floatValues[1]); + ASSERT_EQ(3.402823466E+38f, value->value.floatValues[2]); +} + } // namespace anonymous } // namespace V2_0 diff --git a/automotive/vehicle/2.0/utils/UserHalHelper.cpp b/automotive/vehicle/2.0/utils/UserHalHelper.cpp index abf59b74e3..dccdb2b845 100644 --- a/automotive/vehicle/2.0/utils/UserHalHelper.cpp +++ b/automotive/vehicle/2.0/utils/UserHalHelper.cpp @@ -60,11 +60,22 @@ Result<void> parseUserInfo(const hidl_vec<int32_t>& int32Values, size_t startPos << int32Values.size(); } userInfo->userId = int32Values[startPos]; - auto userFlags = verifyAndCast<UserFlags>(int32Values[startPos + 1]); - if (!userFlags.ok()) { - return Error() << "Invalid user flags: " << userFlags.error(); + int32_t intUserFlags = int32Values[startPos + 1]; + int32_t expectedUserFlags = 0; + for (const auto& v : hidl_enum_range<UserFlags>()) { + int32_t intEnumUserFlag = static_cast<int32_t>(v); + if ((intUserFlags & intEnumUserFlag) != 0) { + expectedUserFlags |= intEnumUserFlag; + } + } + if (intUserFlags != expectedUserFlags) { + return Error() << "Invalid user flags: " << intUserFlags << ", must be '|' of UserFlags"; } - userInfo->flags = *userFlags; + // intUserFlags is actually not a valid UserFlags enum, instead, it is a 'bit or' of possible + // multiple UserFlags. However, because the HAL interface was defined incorrectly, we have to + // cast it to UserFlags here, which is defined behavior because the underlying type for + // UserFlags is int32_t and our intUserFlags is within the range of int32_t. + userInfo->flags = static_cast<UserFlags>(intUserFlags); return {}; } diff --git a/automotive/vehicle/2.0/utils/tests/UserHalHelper_test.cpp b/automotive/vehicle/2.0/utils/tests/UserHalHelper_test.cpp index 7da87a23c8..0562a54cec 100644 --- a/automotive/vehicle/2.0/utils/tests/UserHalHelper_test.cpp +++ b/automotive/vehicle/2.0/utils/tests/UserHalHelper_test.cpp @@ -54,6 +54,10 @@ constexpr int32_t VEHICLE_REQUEST = static_cast<int32_t>(SwitchUserMessageType:: constexpr int32_t GUEST_USER = static_cast<int32_t>(UserFlags::GUEST); constexpr int32_t NONE_USER = static_cast<int32_t>(UserFlags::NONE); constexpr int32_t SYSTEM_USER = static_cast<int32_t>(UserFlags::SYSTEM); +constexpr int32_t ADMIN_USER = static_cast<int32_t>(UserFlags::ADMIN); +constexpr int32_t SYSTEM_ADMIN_USER = static_cast<int32_t>(UserFlags::SYSTEM | UserFlags::ADMIN); +// 0x1111 is not a valid UserFlags combination. +constexpr int32_t INVALID_USER_FLAG = 0x1111; constexpr int32_t USER_ID_ASSOC_KEY_FOB = static_cast<int32_t>(UserIdentificationAssociationType::KEY_FOB); @@ -72,7 +76,7 @@ constexpr int32_t USER_ID_ASSOC_NO_USER = } // namespace -TEST(UserHalHelperTest, TestToInitialUserInfoRequest) { +TEST(UserHalHelperTest, TestToInitialUserInfoRequestSystemUser) { VehiclePropValue propValue{ .prop = INITIAL_USER_INFO, .value = {.int32Values = {23, FIRST_BOOT_AFTER_OTA, 10, NONE_USER, 2, 0, SYSTEM_USER, @@ -92,6 +96,58 @@ TEST(UserHalHelperTest, TestToInitialUserInfoRequest) { EXPECT_THAT(actual.value(), Eq(expected)); } +TEST(UserHalHelperTest, TestToInitialUserInfoRequestAdminUser) { + VehiclePropValue propValue{ + .prop = INITIAL_USER_INFO, + .value = {.int32Values = {23, FIRST_BOOT_AFTER_OTA, 10, NONE_USER, 2, 0, ADMIN_USER, 10, + NONE_USER}}, + }; + InitialUserInfoRequest expected{ + .requestId = 23, + .requestType = InitialUserInfoRequestType::FIRST_BOOT_AFTER_OTA, + .usersInfo = {{10, UserFlags::NONE}, 2, {{0, UserFlags::ADMIN}, {10, UserFlags::NONE}}}, + }; + + auto actual = toInitialUserInfoRequest(propValue); + + ASSERT_TRUE(actual.ok()) << actual.error().message(); + EXPECT_THAT(actual.value(), Eq(expected)); +} + +TEST(UserHalHelperTest, TestToInitialUserInfoRequestUserFlagsBitCombination) { + // SYSTEM_ADMIN_USER is two UserFlags combined and is itself not a defined UserFlags enum. + VehiclePropValue propValue{ + .prop = INITIAL_USER_INFO, + .value = {.int32Values = {23, FIRST_BOOT_AFTER_OTA, 10, NONE_USER, 2, 0, + SYSTEM_ADMIN_USER, 10, NONE_USER}}, + }; + InitialUserInfoRequest expected{ + .requestId = 23, + .requestType = InitialUserInfoRequestType::FIRST_BOOT_AFTER_OTA, + .usersInfo = {{10, UserFlags::NONE}, + 2, + {{0, static_cast<UserFlags>(SYSTEM_ADMIN_USER)}, {10, UserFlags::NONE}}}, + }; + + auto actual = toInitialUserInfoRequest(propValue); + + ASSERT_TRUE(actual.ok()) << actual.error().message(); + EXPECT_THAT(actual.value(), Eq(expected)); +} + +TEST(UserHalHelperTest, TestToInitialUserInfoRequestUserInvalidUserFlag) { + // 0x1111 is not a valid UserFlags flag combination. + VehiclePropValue propValue{ + .prop = INITIAL_USER_INFO, + .value = {.int32Values = {23, FIRST_BOOT_AFTER_OTA, 10, NONE_USER, 2, 0, + INVALID_USER_FLAG, 10, NONE_USER}}, + }; + + auto actual = toInitialUserInfoRequest(propValue); + + EXPECT_FALSE(actual.ok()) << "No error returned on invalid user flags"; +} + TEST(UserHalHelperTest, TestFailsToInitialUserInfoRequestWithMismatchingPropType) { VehiclePropValue propValue{ .prop = INT32_MAX, diff --git a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml index 09463c962f..ea7adc9159 100644 --- a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml +++ b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml @@ -22,8 +22,11 @@ <target_preparer class="com.android.tradefed.targetprep.StopServicesSetup"> </target_preparer> - <target_preparer class="com.android.tradefed.targetprep.DeviceSetup"> - <option name="bluetooth" value="off" /> + <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer"> + <option name="run-command" value="settings put global ble_scan_always_enabled 0" /> + <option name="run-command" value="su u$(am get-current-user)_system svc bluetooth disable" /> + <option name="teardown-command" value="su u$(am get-current-user)_system svc bluetooth enable" /> + <option name="teardown-command" value="settings put global ble_scan_always_enabled 1" /> </target_preparer> <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> diff --git a/broadcastradio/2.0/default/Android.bp b/broadcastradio/2.0/default/Android.bp index 870c944d75..38eeb15cdb 100644 --- a/broadcastradio/2.0/default/Android.bp +++ b/broadcastradio/2.0/default/Android.bp @@ -25,6 +25,9 @@ package { cc_binary { name: "android.hardware.broadcastradio@2.0-service", + vintf_fragments: [ + "android.hardware.broadcastradio@2.0-service.xml", + ], init_rc: ["android.hardware.broadcastradio@2.0-service.rc"], vendor: true, relative_install_path: "hw", @@ -41,7 +44,7 @@ cc_binary { "TunerSession.cpp", "VirtualProgram.cpp", "VirtualRadio.cpp", - "service.cpp" + "service.cpp", ], static_libs: [ "android.hardware.broadcastradio@common-utils-2x-lib", diff --git a/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.xml b/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.xml new file mode 100644 index 0000000000..97f2e4d848 --- /dev/null +++ b/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.xml @@ -0,0 +1,12 @@ +<manifest version="1.0" type="device"> + <hal format="hidl"> + <name>android.hardware.broadcastradio</name> + <transport>hwbinder</transport> + <version>2.0</version> + <interface> + <name>IBroadcastRadio</name> + <instance>amfm</instance> + <instance>dab</instance> + </interface> + </hal> +</manifest> diff --git a/camera/metadata/3.7/types.hal b/camera/metadata/3.7/types.hal new file mode 100644 index 0000000000..a09bdf9977 --- /dev/null +++ b/camera/metadata/3.7/types.hal @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2021 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. + */ + +/* + * Autogenerated from camera metadata definitions in + * /system/media/camera/docs/metadata_definitions.xml + * *** DO NOT EDIT BY HAND *** + */ + +package android.hardware.camera.metadata@3.7; + +import android.hardware.camera.metadata@3.2; +import android.hardware.camera.metadata@3.3; +import android.hardware.camera.metadata@3.4; +import android.hardware.camera.metadata@3.5; +import android.hardware.camera.metadata@3.6; + +// No new metadata sections added in this revision + +/** + * Main enumeration for defining camera metadata tags added in this revision + * + * <p>Partial documentation is included for each tag; for complete documentation, reference + * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.</p> + */ +enum CameraMetadataTag : @3.6::CameraMetadataTag { + /** android.info.deviceStateOrientations [static, int64[], ndk_public] + */ + ANDROID_INFO_DEVICE_STATE_ORIENTATIONS = android.hardware.camera.metadata@3.4::CameraMetadataTag:ANDROID_INFO_END_3_4, + + ANDROID_INFO_END_3_7, + +}; + +/* + * Enumeration definitions for the various entries that need them + */ diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp index 7727547e7d..052103d784 100644 --- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp +++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp @@ -882,6 +882,7 @@ public: camera_metadata* oldSessionParams, camera_metadata* newSessionParams); void verifyRequestTemplate(const camera_metadata_t* metadata, RequestTemplate requestTemplate); + static void overrideRotateAndCrop(::android::hardware::hidl_vec<uint8_t> *settings /*in/out*/); static bool isDepthOnly(const camera_metadata_t* staticMeta); @@ -935,7 +936,9 @@ public: camera_metadata_ro_entry* streamConfigs, camera_metadata_ro_entry* maxResolutionStreamConfigs, const camera_metadata_t* staticMetadata); - static bool isColorCamera(const camera_metadata_t *metadata); + void getPrivacyTestPatternModes( + const camera_metadata_t* staticMetadata, + std::unordered_set<int32_t>* privacyTestPatternModes/*out*/); static V3_2::DataspaceFlags getDataspace(PixelFormat format); @@ -4660,6 +4663,7 @@ void CameraHidlTest::processCaptureRequestInternal(uint64_t bufferUsage, settings = req; }); ASSERT_TRUE(ret.isOk()); + overrideRotateAndCrop(&settings); hidl_handle buffer_handle; StreamBuffer outputBuffer; @@ -4836,6 +4840,7 @@ TEST_P(CameraHidlTest, processMultiCaptureRequestPreview) { settings.setToExternal( reinterpret_cast<uint8_t *> (const_cast<camera_metadata_t *> (settingsBuffer)), get_camera_metadata_size(settingsBuffer)); + overrideRotateAndCrop(&settings); free_camera_metadata(staticMeta); ret = session->close(); @@ -4913,6 +4918,7 @@ TEST_P(CameraHidlTest, processMultiCaptureRequestPreview) { reinterpret_cast<uint8_t *> (const_cast<camera_metadata_t *> ( filteredSettingsBuffer)), get_camera_metadata_size(filteredSettingsBuffer)); + overrideRotateAndCrop(&camSettings[0].settings); camSettings[0].fmqSettingsSize = 0; camSettings[0].physicalCameraId = physicalDeviceId; @@ -5070,6 +5076,7 @@ TEST_P(CameraHidlTest, processUltraHighResolutionRequest) { settings.setToExternal( reinterpret_cast<uint8_t*>(const_cast<camera_metadata_t*>(settingsBuffer)), get_camera_metadata_size(settingsBuffer)); + overrideRotateAndCrop(&settings); free_camera_metadata(staticMeta); ret = session->close(); @@ -5305,6 +5312,7 @@ TEST_P(CameraHidlTest, processCaptureRequestBurstISO) { camera_metadata_t *metaBuffer = requestMeta.release(); requestSettings[i].setToExternal(reinterpret_cast<uint8_t *> (metaBuffer), get_camera_metadata_size(metaBuffer), true); + overrideRotateAndCrop(&requestSettings[i]); requests[i] = {frameNumber + i, 0 /* fmqSettingsSize */, requestSettings[i], emptyInputBuffer, {outputBuffers[i]}}; @@ -5531,6 +5539,7 @@ TEST_P(CameraHidlTest, switchToOffline) { camera_metadata_t *metaBuffer = requestMeta.release(); requestSettings[i].setToExternal(reinterpret_cast<uint8_t *> (metaBuffer), get_camera_metadata_size(metaBuffer), true); + overrideRotateAndCrop(&requestSettings[i]); requests[i] = {frameNumber + i, 0 /* fmqSettingsSize */, requestSettings[i], emptyInputBuffer, {outputBuffers[i]}}; @@ -5671,6 +5680,7 @@ TEST_P(CameraHidlTest, processCaptureRequestInvalidBuffer) { settings = req; }); ASSERT_TRUE(ret.isOk()); + overrideRotateAndCrop(&settings); ::android::hardware::hidl_vec<StreamBuffer> emptyOutputBuffers; StreamBuffer emptyInputBuffer = {-1, 0, nullptr, BufferStatus::ERROR, nullptr, @@ -5755,6 +5765,7 @@ TEST_P(CameraHidlTest, flushPreviewRequest) { settings = req; }); ASSERT_TRUE(ret.isOk()); + overrideRotateAndCrop(&settings); hidl_handle buffer_handle; if (useHalBufManager) { @@ -6187,167 +6198,6 @@ TEST_P(CameraHidlTest, configureInjectionStreamsWithSessionParameters) { } } -// Test the multi-camera API requirement for Google Requirement Freeze S -// Note that this requirement can only be partially tested. If a vendor -// device doesn't expose a physical camera in any shape or form, there is no way -// the test can catch it. -TEST_P(CameraHidlTest, grfSMultiCameraTest) { - const int socGrfApi = property_get_int32("ro.board.first_api_level", /*default*/ -1); - if (socGrfApi < 31 /*S*/) { - // Non-GRF devices, or version < 31 Skip - ALOGI("%s: socGrfApi level is %d. Skipping", __FUNCTION__, socGrfApi); - return; - } - - // Test that if more than one color cameras facing the same direction are - // supported, there must be at least one logical camera facing that - // direction. - hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider); - // Front and back facing non-logical color cameras - std::set<std::string> frontColorCameras, rearColorCameras; - // Front and back facing logical cameras' physical camera Id sets - std::set<std::set<std::string>> frontPhysicalIds, rearPhysicalIds; - for (const auto& name : cameraDeviceNames) { - std::string cameraId; - int deviceVersion = getCameraDeviceVersionAndId(name, mProviderType, &cameraId); - switch (deviceVersion) { - case CAMERA_DEVICE_API_VERSION_3_7: - case CAMERA_DEVICE_API_VERSION_3_6: - case CAMERA_DEVICE_API_VERSION_3_5: - case CAMERA_DEVICE_API_VERSION_3_4: - case CAMERA_DEVICE_API_VERSION_3_3: - case CAMERA_DEVICE_API_VERSION_3_2: { - ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x; - ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str()); - Return<void> ret; - ret = mProvider->getCameraDeviceInterface_V3_x( - name, [&](auto status, const auto& device) { - ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status); - ASSERT_EQ(Status::OK, status); - ASSERT_NE(device, nullptr); - device3_x = device; - }); - ASSERT_TRUE(ret.isOk()); - - ret = device3_x->getCameraCharacteristics([&](auto status, const auto& chars) { - ASSERT_EQ(Status::OK, status); - const camera_metadata_t* metadata = (camera_metadata_t*)chars.data(); - - // Skip if this is not a color camera. - if (!CameraHidlTest::isColorCamera(metadata)) { - return; - } - - // Check camera facing. Skip if facing is neither FRONT - // nor BACK. If this is not a logical camera, only note down - // the camera ID, and skip. - camera_metadata_ro_entry entry; - int retcode = find_camera_metadata_ro_entry( - metadata, ANDROID_LENS_FACING, &entry); - ASSERT_EQ(retcode, 0); - ASSERT_GT(entry.count, 0); - uint8_t facing = entry.data.u8[0]; - bool isLogicalCamera = (isLogicalMultiCamera(metadata) == Status::OK); - if (facing == ANDROID_LENS_FACING_FRONT) { - if (!isLogicalCamera) { - frontColorCameras.insert(cameraId); - return; - } - } else if (facing == ANDROID_LENS_FACING_BACK) { - if (!isLogicalCamera) { - rearColorCameras.insert(cameraId); - return; - } - } else { - // Not FRONT or BACK facing. Skip. - return; - } - - // Check logical camera's physical camera IDs for color - // cameras. - std::unordered_set<std::string> physicalCameraIds; - Status s = getPhysicalCameraIds(metadata, &physicalCameraIds); - ASSERT_EQ(Status::OK, s); - if (facing == ANDROID_LENS_FACING_FRONT) { - frontPhysicalIds.emplace(physicalCameraIds.begin(), physicalCameraIds.end()); - } else { - rearPhysicalIds.emplace(physicalCameraIds.begin(), physicalCameraIds.end()); - } - for (const auto& physicalId : physicalCameraIds) { - // Skip if the physicalId is publicly available - for (auto& deviceName : cameraDeviceNames) { - std::string publicVersion, publicId; - ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType, - &publicVersion, &publicId)); - if (physicalId == publicId) { - // Skip because public Ids will be iterated in outer loop. - return; - } - } - - auto castResult = device::V3_5::ICameraDevice::castFrom(device3_x); - ASSERT_TRUE(castResult.isOk()); - ::android::sp<::android::hardware::camera::device::V3_5::ICameraDevice> - device3_5 = castResult; - ASSERT_NE(device3_5, nullptr); - - // Check camera characteristics for hidden camera id - Return<void> ret = device3_5->getPhysicalCameraCharacteristics( - physicalId, [&](auto status, const auto& chars) { - ASSERT_EQ(Status::OK, status); - const camera_metadata_t* physicalMetadata = - (camera_metadata_t*)chars.data(); - - if (CameraHidlTest::isColorCamera(physicalMetadata)) { - if (facing == ANDROID_LENS_FACING_FRONT) { - frontColorCameras.insert(physicalId); - } else if (facing == ANDROID_LENS_FACING_BACK) { - rearColorCameras.insert(physicalId); - } - } - }); - ASSERT_TRUE(ret.isOk()); - } - }); - ASSERT_TRUE(ret.isOk()); - } break; - case CAMERA_DEVICE_API_VERSION_1_0: { - // Not applicable - } break; - default: { - ALOGE("%s: Unsupported device version %d", __func__, deviceVersion); - ADD_FAILURE(); - } break; - } - } - - // If there are more than one color cameras facing one direction, a logical - // multi-camera must be defined consisting of all color cameras facing that - // direction. - if (frontColorCameras.size() > 1) { - bool hasFrontLogical = false; - for (const auto& physicalIds : frontPhysicalIds) { - if (std::includes(physicalIds.begin(), physicalIds.end(), - frontColorCameras.begin(), frontColorCameras.end())) { - hasFrontLogical = true; - break; - } - } - ASSERT_TRUE(hasFrontLogical); - } - if (rearColorCameras.size() > 1) { - bool hasRearLogical = false; - for (const auto& physicalIds : rearPhysicalIds) { - if (std::includes(physicalIds.begin(), physicalIds.end(), - rearColorCameras.begin(), rearColorCameras.end())) { - hasRearLogical = true; - break; - } - } - ASSERT_TRUE(hasRearLogical); - } -} - // Retrieve all valid output stream resolutions from the camera // static characteristics. Status CameraHidlTest::getAvailableOutputStreams(const camera_metadata_t* staticMeta, @@ -6779,6 +6629,25 @@ void CameraHidlTest::getMultiResolutionStreamConfigurations( ASSERT_TRUE(-ENOENT == retcode || 0 == retcode); } +void CameraHidlTest::getPrivacyTestPatternModes( + const camera_metadata_t* staticMetadata, + std::unordered_set<int32_t>* privacyTestPatternModes/*out*/) { + ASSERT_NE(staticMetadata, nullptr); + ASSERT_NE(privacyTestPatternModes, nullptr); + + camera_metadata_ro_entry entry; + int retcode = find_camera_metadata_ro_entry( + staticMetadata, ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES, &entry); + ASSERT_TRUE(0 == retcode); + + for (auto i = 0; i < entry.count; i++) { + if (entry.data.i32[i] == ANDROID_SENSOR_TEST_PATTERN_MODE_SOLID_COLOR || + entry.data.i32[i] == ANDROID_SENSOR_TEST_PATTERN_MODE_BLACK) { + privacyTestPatternModes->insert(entry.data.i32[i]); + } + } +} + // Select an appropriate dataspace given a specific pixel format. V3_2::DataspaceFlags CameraHidlTest::getDataspace(PixelFormat format) { switch (format) { @@ -6820,23 +6689,6 @@ Status CameraHidlTest::isMonochromeCamera(const camera_metadata_t *staticMeta) { return ret; } -bool CameraHidlTest::isColorCamera(const camera_metadata_t *metadata) { - camera_metadata_ro_entry entry; - int retcode = find_camera_metadata_ro_entry( - metadata, ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry); - if ((0 == retcode) && (entry.count > 0)) { - bool isBackwardCompatible = (std::find(entry.data.u8, entry.data.u8 + entry.count, - ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) != - entry.data.u8 + entry.count); - bool isMonochrome = (std::find(entry.data.u8, entry.data.u8 + entry.count, - ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) != - entry.data.u8 + entry.count); - bool isColor = isBackwardCompatible && !isMonochrome; - return isColor; - } - return false; -} - // Retrieve the reprocess input-output format map from the static // camera characteristics. Status CameraHidlTest::getZSLInputOutputMap(camera_metadata_t *staticMeta, @@ -7833,6 +7685,16 @@ void CameraHidlTest::verifyLogicalOrUltraHighResCameraMetadata( ASSERT_TRUE(isUltraHighResCamera && !isMultiCamera); physicalIds.insert(cameraId); } + + std::unordered_set<int32_t> physicalRequestKeyIDs; + rc = getSupportedKeys(const_cast<camera_metadata_t *>(metadata), + ANDROID_REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS, &physicalRequestKeyIDs); + ASSERT_TRUE(Status::OK == rc); + bool hasTestPatternPhysicalRequestKey = physicalRequestKeyIDs.find( + ANDROID_SENSOR_TEST_PATTERN_MODE) != physicalRequestKeyIDs.end(); + std::unordered_set<int32_t> privacyTestPatternModes; + getPrivacyTestPatternModes(metadata, &privacyTestPatternModes); + // Map from image format to number of multi-resolution sizes for that format std::unordered_map<int32_t, size_t> multiResOutputFormatCounterMap; std::unordered_map<int32_t, size_t> multiResInputFormatCounterMap; @@ -7854,6 +7716,7 @@ void CameraHidlTest::verifyLogicalOrUltraHighResCameraMetadata( camera_metadata_ro_entry physicalStreamConfigs; camera_metadata_ro_entry physicalMaxResolutionStreamConfigs; bool isUltraHighRes = false; + std::unordered_set<int32_t> subCameraPrivacyTestPatterns; if (isPublicId) { ::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> subDevice; Return<void> ret; @@ -7884,6 +7747,8 @@ void CameraHidlTest::verifyLogicalOrUltraHighResCameraMetadata( &physicalMultiResStreamConfigs, &physicalStreamConfigs, &physicalMaxResolutionStreamConfigs, staticMetadata); isUltraHighRes = isUltraHighResolution(staticMetadata); + + getPrivacyTestPatternModes(staticMetadata, &subCameraPrivacyTestPatterns); }); ASSERT_TRUE(ret.isOk()); } else { @@ -7910,6 +7775,7 @@ void CameraHidlTest::verifyLogicalOrUltraHighResCameraMetadata( &physicalMultiResStreamConfigs, &physicalStreamConfigs, &physicalMaxResolutionStreamConfigs, staticMetadata); isUltraHighRes = isUltraHighResolution(staticMetadata); + getPrivacyTestPatternModes(staticMetadata, &subCameraPrivacyTestPatterns); }); ASSERT_TRUE(ret.isOk()); @@ -7926,6 +7792,10 @@ void CameraHidlTest::verifyLogicalOrUltraHighResCameraMetadata( ASSERT_TRUE(ret.isOk()); } + if (hasTestPatternPhysicalRequestKey) { + ASSERT_TRUE(privacyTestPatternModes == subCameraPrivacyTestPatterns); + } + if (physicalMultiResStreamConfigs.count > 0) { ASSERT_GE(deviceVersion, CAMERA_DEVICE_API_VERSION_3_7); ASSERT_EQ(physicalMultiResStreamConfigs.count % 4, 0); @@ -8161,6 +8031,20 @@ void CameraHidlTest::verifyCameraCharacteristics(Status status, const CameraMeta poseReference >= ANDROID_LENS_POSE_REFERENCE_PRIMARY_CAMERA); } + retcode = find_camera_metadata_ro_entry(metadata, + ANDROID_INFO_DEVICE_STATE_ORIENTATIONS, &entry); + if (0 == retcode && entry.count > 0) { + ASSERT_TRUE((entry.count % 2) == 0); + uint64_t maxPublicState = ((uint64_t) provider::V2_5::DeviceState::FOLDED) << 1; + uint64_t vendorStateStart = 1UL << 31; // Reserved for vendor specific states + uint64_t stateMask = (1 << vendorStateStart) - 1; + stateMask &= ~((1 << maxPublicState) - 1); + for (int i = 0; i < entry.count; i += 2){ + ASSERT_TRUE((entry.data.i64[i] & stateMask) == 0); + ASSERT_TRUE((entry.data.i64[i+1] % 90) == 0); + } + } + verifyExtendedSceneModeCharacteristics(metadata); verifyZoomCharacteristics(metadata); } @@ -8921,6 +8805,25 @@ void CameraHidlTest::verifyRequestTemplate(const camera_metadata_t* metadata, } } +void CameraHidlTest::overrideRotateAndCrop( + ::android::hardware::hidl_vec<uint8_t> *settings /*in/out*/) { + if (settings == nullptr) { + return; + } + + ::android::hardware::camera::common::V1_0::helper::CameraMetadata requestMeta; + requestMeta.append(reinterpret_cast<camera_metadata_t *> (settings->data())); + auto entry = requestMeta.find(ANDROID_SCALER_ROTATE_AND_CROP); + if ((entry.count > 0) && (entry.data.u8[0] == ANDROID_SCALER_ROTATE_AND_CROP_AUTO)) { + uint8_t disableRotateAndCrop = ANDROID_SCALER_ROTATE_AND_CROP_NONE; + requestMeta.update(ANDROID_SCALER_ROTATE_AND_CROP, &disableRotateAndCrop, 1); + settings->releaseData(); + camera_metadata_t *metaBuffer = requestMeta.release(); + settings->setToExternal(reinterpret_cast<uint8_t *> (metaBuffer), + get_camera_metadata_size(metaBuffer), true); + } +} + GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CameraHidlTest); INSTANTIATE_TEST_SUITE_P( PerInstance, CameraHidlTest, diff --git a/current.txt b/current.txt index 3893d07354..2373c391d7 100644 --- a/current.txt +++ b/current.txt @@ -901,4 +901,7 @@ c8a57364f6ad20842be14f4db284df5304f7521ca8eac6bcc1fa6c5b466fb8a6 android.hardwar 4a087a308608d146b022ebc15633de989f5f4dfe1491a83fa41763290a82e40d android.hardware.automotive.vehicle@2.0::types 70eb14415391f835fb218b43a1e25f5d6495f098f96fa2acaea70985e98e1ce8 android.hardware.automotive.vehicle@2.0::types +# HALs released in Android SCv2 +77f6fcf3fd0dd3e424d8a0292094ebd17e4c35454bb9abbd3a6cbed1aba70765 android.hardware.camera.metadata@3.7::types + # There should be no more HIDL HALs - please use AIDL instead. diff --git a/gnss/aidl/default/GnssMeasurementInterface.cpp b/gnss/aidl/default/GnssMeasurementInterface.cpp index fcc1f986cc..9e4f7c7f25 100644 --- a/gnss/aidl/default/GnssMeasurementInterface.cpp +++ b/gnss/aidl/default/GnssMeasurementInterface.cpp @@ -19,11 +19,17 @@ #include "GnssMeasurementInterface.h" #include <aidl/android/hardware/gnss/BnGnss.h> #include <log/log.h> +#include "DeviceFileReader.h" +#include "GnssRawMeasurementParser.h" +#include "GnssReplayUtils.h" #include "Utils.h" namespace aidl::android::hardware::gnss { using Utils = ::android::hardware::gnss::common::Utils; +using ReplayUtils = ::android::hardware::gnss::common::ReplayUtils; +using GnssRawMeasurementParser = ::android::hardware::gnss::common::GnssRawMeasurementParser; +using DeviceFileReader = ::android::hardware::gnss::common::DeviceFileReader; std::shared_ptr<IGnssMeasurementCallback> GnssMeasurementInterface::sCallback = nullptr; @@ -63,9 +69,22 @@ void GnssMeasurementInterface::start(const bool enableCorrVecOutputs) { mIsActive = true; mThread = std::thread([this, enableCorrVecOutputs]() { while (mIsActive == true) { - auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs); - this->reportMeasurement(measurement); - + std::string rawMeasurementStr = ""; + if (ReplayUtils::hasGnssDeviceFile() && + ReplayUtils::isGnssRawMeasurement( + rawMeasurementStr = + DeviceFileReader::Instance().getGnssRawMeasurementData())) { + ALOGD("rawMeasurementStr(size: %zu) from device file: %s", rawMeasurementStr.size(), + rawMeasurementStr.c_str()); + auto measurement = + GnssRawMeasurementParser::getMeasurementFromStrs(rawMeasurementStr); + if (measurement != nullptr) { + this->reportMeasurement(*measurement); + } + } else { + auto measurement = Utils::getMockMeasurement(enableCorrVecOutputs); + this->reportMeasurement(measurement); + } std::this_thread::sleep_for(std::chrono::milliseconds(mMinIntervalMillis)); } }); diff --git a/gnss/common/utils/default/Android.bp b/gnss/common/utils/default/Android.bp index 43db8739d1..bdb1569105 100644 --- a/gnss/common/utils/default/Android.bp +++ b/gnss/common/utils/default/Android.bp @@ -38,9 +38,14 @@ cc_library_static { "v2_1/GnssDebug.cpp", "v2_1/GnssMeasurement.cpp", "v2_1/GnssMeasurementCorrections.cpp", + "DeviceFileReader.cpp", + "FixLocationParser.cpp", + "GnssRawMeasurementParser.cpp", + "GnssReplayUtils.cpp", "MockLocation.cpp", - "Utils.cpp", "NmeaFixInfo.cpp", + "ParseUtils.cpp", + "Utils.cpp", ], export_include_dirs: ["include"], shared_libs: [ diff --git a/gnss/common/utils/default/DeviceFileReader.cpp b/gnss/common/utils/default/DeviceFileReader.cpp new file mode 100644 index 0000000000..dfc086a8b8 --- /dev/null +++ b/gnss/common/utils/default/DeviceFileReader.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2021 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 "DeviceFileReader.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +void DeviceFileReader::getDataFromDeviceFile(const std::string& command, int mMinIntervalMs) { + char inputBuffer[INPUT_BUFFER_SIZE]; + std::string deviceFilePath = ""; + if (command == CMD_GET_LOCATION) { + deviceFilePath = ReplayUtils::getFixedLocationPath(); + } else if (command == CMD_GET_RAWMEASUREMENT) { + deviceFilePath = ReplayUtils::getGnssPath(); + } else { + // Invalid command + return; + } + + int mGnssFd = open(deviceFilePath.c_str(), O_RDWR | O_NONBLOCK); + + if (mGnssFd == -1) { + return; + } + + int bytes_write = write(mGnssFd, command.c_str(), command.size()); + if (bytes_write <= 0) { + close(mGnssFd); + return; + } + + struct epoll_event ev, events[1]; + ev.data.fd = mGnssFd; + ev.events = EPOLLIN; + int epoll_fd = epoll_create1(0); + epoll_ctl(epoll_fd, EPOLL_CTL_ADD, mGnssFd, &ev); + int bytes_read = -1; + std::string inputStr = ""; + int epoll_ret = epoll_wait(epoll_fd, events, 1, mMinIntervalMs); + + if (epoll_ret == -1) { + close(mGnssFd); + return; + } + while (true) { + memset(inputBuffer, 0, INPUT_BUFFER_SIZE); + bytes_read = read(mGnssFd, &inputBuffer, INPUT_BUFFER_SIZE); + if (bytes_read <= 0) { + break; + } + s_buffer_ += std::string(inputBuffer, bytes_read); + } + close(mGnssFd); + + // Trim end of file mark(\n\n\n\n). + auto pos = s_buffer_.find("\n\n\n\n"); + if (pos != std::string::npos) { + inputStr = s_buffer_.substr(0, pos); + s_buffer_ = s_buffer_.substr(pos + 4); + } else { + return; + } + + // Cache the injected data. + if (command == CMD_GET_LOCATION) { + // TODO validate data + data_[CMD_GET_LOCATION] = inputStr; + } else if (command == CMD_GET_RAWMEASUREMENT) { + if (ReplayUtils::isGnssRawMeasurement(inputStr)) { + data_[CMD_GET_RAWMEASUREMENT] = inputStr; + } + } +} + +std::string DeviceFileReader::getLocationData() { + std::unique_lock<std::mutex> lock(mMutex); + getDataFromDeviceFile(CMD_GET_LOCATION, 20); + return data_[CMD_GET_LOCATION]; +} + +std::string DeviceFileReader::getGnssRawMeasurementData() { + std::unique_lock<std::mutex> lock(mMutex); + getDataFromDeviceFile(CMD_GET_RAWMEASUREMENT, 20); + return data_[CMD_GET_RAWMEASUREMENT]; +} + +DeviceFileReader::DeviceFileReader() {} + +DeviceFileReader::~DeviceFileReader() {} + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/common/utils/default/FixLocationParser.cpp b/gnss/common/utils/default/FixLocationParser.cpp new file mode 100644 index 0000000000..f0177b49c5 --- /dev/null +++ b/gnss/common/utils/default/FixLocationParser.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "FixLocationParser.h" + +#include <android/hardware/gnss/1.0/IGnss.h> + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +std::unique_ptr<V2_0::GnssLocation> FixLocationParser::getLocationFromInputStr( + const std::string& locationStr) { + /* + * Fix,Provider,LatitudeDegrees,LongitudeDegrees,AltitudeMeters,SpeedMps, + * AccuracyMeters,BearingDegrees,UnixTimeMillis,SpeedAccuracyMps,BearingAccuracyDegrees, + * elapsedRealtimeNanos + */ + if (locationStr.empty()) { + return nullptr; + } + std::vector<std::string> locationStrRecords; + ParseUtils::splitStr(locationStr, LINE_SEPARATOR, locationStrRecords); + if (locationStrRecords.empty()) { + return nullptr; + } + + std::vector<std::string> locationValues; + ParseUtils::splitStr(locationStrRecords[0], COMMA_SEPARATOR, locationValues); + if (locationValues.size() < 12) { + return nullptr; + } + V2_0::ElapsedRealtime elapsedRealtime = { + .flags = V2_0::ElapsedRealtimeFlags::HAS_TIMESTAMP_NS | + V2_0::ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS, + .timestampNs = static_cast<uint64_t>(::android::elapsedRealtimeNano()), + // This is an hardcoded value indicating a 1ms of uncertainty between the two clocks. + // In an actual implementation provide an estimate of the synchronization uncertainty + // or don't set the field. + .timeUncertaintyNs = 1020400}; + + V1_0::GnssLocation locationV1 = { + .gnssLocationFlags = 0xFF, + .latitudeDegrees = ParseUtils::tryParseDouble(locationValues[2], 0), + .longitudeDegrees = ParseUtils::tryParseDouble(locationValues[3], 0), + .altitudeMeters = ParseUtils::tryParseDouble(locationValues[4], 0), + .speedMetersPerSec = ParseUtils::tryParsefloat(locationValues[5], 0), + .bearingDegrees = ParseUtils::tryParsefloat(locationValues[7], 0), + .horizontalAccuracyMeters = ParseUtils::tryParsefloat(locationValues[6], 0), + .verticalAccuracyMeters = ParseUtils::tryParsefloat(locationValues[6], 0), + .speedAccuracyMetersPerSecond = ParseUtils::tryParsefloat(locationValues[9], 0), + .bearingAccuracyDegrees = ParseUtils::tryParsefloat(locationValues[10], 0), + .timestamp = ParseUtils::tryParseLongLong(locationValues[8], 0)}; + + V2_0::GnssLocation locationV2 = {.v1_0 = locationV1, .elapsedRealtime = elapsedRealtime}; + return std::make_unique<V2_0::GnssLocation>(locationV2); +} + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/common/utils/default/GnssRawMeasurementParser.cpp b/gnss/common/utils/default/GnssRawMeasurementParser.cpp new file mode 100644 index 0000000000..c066229ae9 --- /dev/null +++ b/gnss/common/utils/default/GnssRawMeasurementParser.cpp @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2021 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 "GnssRawMeasurementParser.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +using aidl::android::hardware::gnss::ElapsedRealtime; +using aidl::android::hardware::gnss::GnssClock; +using aidl::android::hardware::gnss::GnssConstellationType; +using aidl::android::hardware::gnss::GnssData; +using aidl::android::hardware::gnss::GnssMeasurement; +using aidl::android::hardware::gnss::GnssMultipathIndicator; +using aidl::android::hardware::gnss::GnssSignalType; + +using ParseUtils = ::android::hardware::gnss::common::ParseUtils; + +std::unordered_map<std::string, int> GnssRawMeasurementParser::getColumnIdNameMappingFromHeader( + const std::string& header) { + std::vector<std::string> columnNames; + std::unordered_map<std::string, int> columnNameIdMapping; + std::string s = header; + // Trim left spaces + s.erase(s.begin(), + std::find_if(s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); })); + // Trim right spaces + s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); }) + .base(), + s.end()); + // Remove comment symbol, start from `Raw`. + s = s.substr(s.find("Raw")); + + ParseUtils::splitStr(s, COMMA_SEPARATOR, columnNames); + int columnId = 0; + for (auto& name : columnNames) { + columnNameIdMapping[name] = columnId++; + } + + return columnNameIdMapping; +} + +int GnssRawMeasurementParser::getClockFlags( + const std::vector<std::string>& rawMeasurementRecordValues, + const std::unordered_map<std::string, int>& columnNameIdMapping) { + int clockFlags = 0; + if (!rawMeasurementRecordValues[columnNameIdMapping.at("LeapSecond")].empty()) { + clockFlags |= GnssClock::HAS_LEAP_SECOND; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("FullBiasNanos")].empty()) { + clockFlags |= GnssClock::HAS_FULL_BIAS; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("BiasNanos")].empty()) { + clockFlags |= GnssClock::HAS_BIAS; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("BiasUncertaintyNanos")].empty()) { + clockFlags |= GnssClock::HAS_BIAS_UNCERTAINTY; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("DriftNanosPerSecond")].empty()) { + clockFlags |= GnssClock::HAS_DRIFT; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("DriftUncertaintyNanosPerSecond")] + .empty()) { + clockFlags |= GnssClock::HAS_DRIFT_UNCERTAINTY; + } + return clockFlags; +} + +int GnssRawMeasurementParser::getElapsedRealtimeFlags( + const std::vector<std::string>& rawMeasurementRecordValues, + const std::unordered_map<std::string, int>& columnNameIdMapping) { + int elapsedRealtimeFlags = ElapsedRealtime::HAS_TIMESTAMP_NS; + if (!rawMeasurementRecordValues[columnNameIdMapping.at("TimeUncertaintyNanos")].empty()) { + elapsedRealtimeFlags |= ElapsedRealtime::HAS_TIME_UNCERTAINTY_NS; + } + return elapsedRealtimeFlags; +} + +int GnssRawMeasurementParser::getRawMeasurementFlags( + const std::vector<std::string>& rawMeasurementRecordValues, + const std::unordered_map<std::string, int>& columnNameIdMapping) { + int rawMeasurementFlags = 0; + if (!rawMeasurementRecordValues[columnNameIdMapping.at("SnrInDb")].empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_SNR; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("CarrierFrequencyHz")].empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_CARRIER_FREQUENCY; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("CarrierCycles")].empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_CARRIER_CYCLES; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("CarrierPhase")].empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_CARRIER_PHASE; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("CarrierPhaseUncertainty")].empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_CARRIER_PHASE_UNCERTAINTY; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("AgcDb")].empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_AUTOMATIC_GAIN_CONTROL; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("FullInterSignalBiasNanos")].empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_FULL_ISB; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("FullInterSignalBiasUncertaintyNanos")] + .empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_FULL_ISB_UNCERTAINTY; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at("SatelliteInterSignalBiasNanos")] + .empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_SATELLITE_ISB; + } + if (!rawMeasurementRecordValues[columnNameIdMapping.at( + "SatelliteInterSignalBiasUncertaintyNanos")] + .empty()) { + rawMeasurementFlags |= GnssMeasurement::HAS_SATELLITE_ISB_UNCERTAINTY; + } + // HAS_SATELLITE_PVT and HAS_CORRELATION_VECTOR fields currently not in rawmeasurement + // output, need add them later. + return rawMeasurementFlags; +} + +GnssConstellationType GnssRawMeasurementParser::getGnssConstellationType(int constellationType) { + GnssConstellationType gnssConstellationType = + aidl::android::hardware::gnss::GnssConstellationType::UNKNOWN; + + switch (constellationType) { + case 1: + gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::GPS; + break; + case 2: + gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::SBAS; + break; + case 3: + gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::GLONASS; + break; + case 4: + gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::QZSS; + break; + case 5: + gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::BEIDOU; + break; + case 6: + gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::GALILEO; + break; + default: + gnssConstellationType = aidl::android::hardware::gnss::GnssConstellationType::UNKNOWN; + } + + return gnssConstellationType; +} + +std::unique_ptr<GnssData> GnssRawMeasurementParser::getMeasurementFromStrs( + std::string& rawMeasurementStr) { + /* + * Raw,utcTimeMillis,TimeNanos,LeapSecond,TimeUncertaintyNanos,FullBiasNanos,BiasNanos, + * BiasUncertaintyNanos,DriftNanosPerSecond,DriftUncertaintyNanosPerSecond, + * HardwareClockDiscontinuityCount,Svid,TimeOffsetNanos,State,ReceivedSvTimeNanos, + * ReceivedSvTimeUncertaintyNanos,Cn0DbHz,PseudorangeRateMetersPerSecond, + * PseudorangeRateUncertaintyMetersPerSecond,AccumulatedDeltaRangeState, + * AccumulatedDeltaRangeMeters,AccumulatedDeltaRangeUncertaintyMeters,CarrierFrequencyHz, + * CarrierCycles,CarrierPhase,CarrierPhaseUncertainty,MultipathIndicator,SnrInDb, + * ConstellationType,AgcDb,BasebandCn0DbHz,FullInterSignalBiasNanos, + * FullInterSignalBiasUncertaintyNanos,SatelliteInterSignalBiasNanos, + * SatelliteInterSignalBiasUncertaintyNanos,CodeType,ChipsetElapsedRealtimeNanos + */ + ALOGD("Parsing %zu bytes rawMeasurementStr.", rawMeasurementStr.size()); + if (rawMeasurementStr.empty()) { + return nullptr; + } + std::vector<std::string> rawMeasurementStrRecords; + ParseUtils::splitStr(rawMeasurementStr, LINE_SEPARATOR, rawMeasurementStrRecords); + if (rawMeasurementStrRecords.size() <= 1) { + ALOGE("Raw GNSS Measurements parser failed. (No records) "); + return nullptr; + } + + // Get the column name mapping from the header. + std::unordered_map<std::string, int> columnNameIdMapping = + getColumnIdNameMappingFromHeader(rawMeasurementStrRecords[0]); + + if (columnNameIdMapping.size() < 37 || !ParseUtils::isValidHeader(columnNameIdMapping)) { + ALOGE("Raw GNSS Measurements parser failed. (No header or missing columns.) "); + return nullptr; + } + + // Set GnssClock from 1st record. + std::size_t pointer = 1; + std::vector<std::string> firstRecordValues; + ParseUtils::splitStr(rawMeasurementStrRecords[pointer], COMMA_SEPARATOR, firstRecordValues); + GnssClock clock = { + .gnssClockFlags = getClockFlags(firstRecordValues, columnNameIdMapping), + .timeNs = ParseUtils::tryParseLongLong( + firstRecordValues[columnNameIdMapping.at("TimeNanos")], 0), + .fullBiasNs = ParseUtils::tryParseLongLong( + firstRecordValues[columnNameIdMapping.at("FullBiasNanos")], 0), + .biasNs = ParseUtils::tryParseDouble( + firstRecordValues[columnNameIdMapping.at("BiasNanos")], 0), + .biasUncertaintyNs = ParseUtils::tryParseDouble( + firstRecordValues[columnNameIdMapping.at("BiasUncertaintyNanos")], 0), + .driftNsps = ParseUtils::tryParseDouble( + firstRecordValues[columnNameIdMapping.at("DriftNanosPerSecond")], 0), + .driftUncertaintyNsps = ParseUtils::tryParseDouble( + firstRecordValues[columnNameIdMapping.at("DriftNanosPerSecond")], 0), + .hwClockDiscontinuityCount = ParseUtils::tryParseInt( + firstRecordValues[columnNameIdMapping.at("HardwareClockDiscontinuityCount")], + 0)}; + + ElapsedRealtime timestamp = { + .flags = getElapsedRealtimeFlags(firstRecordValues, columnNameIdMapping), + .timestampNs = ParseUtils::tryParseLongLong( + firstRecordValues[columnNameIdMapping.at("ChipsetElapsedRealtimeNanos")]), + .timeUncertaintyNs = ParseUtils::tryParseDouble( + firstRecordValues[columnNameIdMapping.at("TimeUncertaintyNanos")], 0)}; + + std::vector<GnssMeasurement> measurementsVec; + for (pointer = 1; pointer < rawMeasurementStrRecords.size(); pointer++) { + std::vector<std::string> rawMeasurementValues; + std::string line = rawMeasurementStrRecords[pointer]; + ParseUtils::splitStr(line, COMMA_SEPARATOR, rawMeasurementValues); + GnssSignalType signalType = { + .constellation = getGnssConstellationType(ParseUtils::tryParseInt( + rawMeasurementValues[columnNameIdMapping.at("ConstellationType")], 0)), + .carrierFrequencyHz = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at("CarrierFrequencyHz")], 0), + .codeType = rawMeasurementValues[columnNameIdMapping.at("CodeType")], + }; + GnssMeasurement measurement = { + .flags = getRawMeasurementFlags(rawMeasurementValues, columnNameIdMapping), + .svid = ParseUtils::tryParseInt( + rawMeasurementValues[columnNameIdMapping.at("Svid")], 0), + .signalType = signalType, + .receivedSvTimeInNs = ParseUtils::tryParseLongLong( + rawMeasurementValues[columnNameIdMapping.at("ReceivedSvTimeNanos")], 0), + .receivedSvTimeUncertaintyInNs = + ParseUtils::tryParseLongLong(rawMeasurementValues[columnNameIdMapping.at( + "ReceivedSvTimeUncertaintyNanos")], + 0), + .antennaCN0DbHz = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at("Cn0DbHz")], 0), + .basebandCN0DbHz = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at("BasebandCn0DbHz")], 0), + .agcLevelDb = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at("AgcDb")], 0), + .pseudorangeRateMps = + ParseUtils::tryParseDouble(rawMeasurementValues[columnNameIdMapping.at( + "PseudorangeRateMetersPerSecond")], + 0), + .pseudorangeRateUncertaintyMps = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at( + "PseudorangeRateUncertaintyMetersPerSecond")], + 0), + .accumulatedDeltaRangeState = ParseUtils::tryParseInt( + rawMeasurementValues[columnNameIdMapping.at("AccumulatedDeltaRangeState")], + 0), + .accumulatedDeltaRangeM = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at("AccumulatedDeltaRangeMeters")], + 0), + .accumulatedDeltaRangeUncertaintyM = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at( + "AccumulatedDeltaRangeUncertaintyMeters")], + 0), + .multipathIndicator = GnssMultipathIndicator::UNKNOWN, // Not in GnssLogger yet. + .state = ParseUtils::tryParseInt( + rawMeasurementValues[columnNameIdMapping.at("State")], 0), + .fullInterSignalBiasNs = ParseUtils::tryParseDouble(rawMeasurementValues[31], 0), + .fullInterSignalBiasUncertaintyNs = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at("FullInterSignalBiasNanos")], + 0), + .satelliteInterSignalBiasNs = + ParseUtils::tryParseDouble(rawMeasurementValues[columnNameIdMapping.at( + "SatelliteInterSignalBiasNanos")], + 0), + .satelliteInterSignalBiasUncertaintyNs = ParseUtils::tryParseDouble( + rawMeasurementValues[columnNameIdMapping.at( + "SatelliteInterSignalBiasUncertaintyNanos")], + 0), + .satellitePvt = {}, + .correlationVectors = {}}; + measurementsVec.push_back(measurement); + } + + GnssData gnssData = { + .measurements = measurementsVec, .clock = clock, .elapsedRealtime = timestamp}; + return std::make_unique<GnssData>(gnssData); +} + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/common/utils/default/GnssReplayUtils.cpp b/gnss/common/utils/default/GnssReplayUtils.cpp new file mode 100644 index 0000000000..d6769bdacc --- /dev/null +++ b/gnss/common/utils/default/GnssReplayUtils.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2021 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 "GnssReplayUtils.h" + +#include <array> + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +std::string ReplayUtils::getGnssPath() { + std::array<char, PROPERTY_VALUE_MAX> devname_value; + + devname_value.fill(0); + if (property_get("debug.location.gnss.devname", devname_value.begin(), NULL) > 0) { + return devname_value.begin(); + } + + devname_value.fill(0); + if (property_get("vendor.ser.gnss-uart", devname_value.begin(), NULL) > 0) { + return devname_value.begin(); + } + + return GNSS_PATH; +} + +std::string ReplayUtils::getFixedLocationPath() { + std::array<char, PROPERTY_VALUE_MAX> devname_value; + + devname_value.fill(0); + if (property_get("debug.location.fixedlocation.devname", devname_value.begin(), NULL) > 0) { + return devname_value.begin(); + } + + devname_value.fill(0); + if (property_get("vendor.ser.gnss-uart", devname_value.begin(), NULL) > 0) { + return devname_value.begin(); + } + + return FIXED_LOCATION_PATH; +} + +bool ReplayUtils::hasGnssDeviceFile() { + struct stat sb; + return stat(getGnssPath().c_str(), &sb) != -1; +} + +bool ReplayUtils::hasFixedLocationDeviceFile() { + struct stat sb; + return stat(getFixedLocationPath().c_str(), &sb) != -1; +} + +bool ReplayUtils::isGnssRawMeasurement(const std::string& inputStr) { + // TODO: add more logic check to by pass invalid data. + return !inputStr.empty() && (inputStr.find("Raw") != std::string::npos); +} + +bool ReplayUtils::isNMEA(const std::string& inputStr) { + return !inputStr.empty() && (inputStr.find("$GPRMC,", 0) != std::string::npos || + inputStr.find("$GPRMA,", 0) != std::string::npos); +} + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/common/utils/default/ParseUtils.cpp b/gnss/common/utils/default/ParseUtils.cpp new file mode 100644 index 0000000000..648edf7ecd --- /dev/null +++ b/gnss/common/utils/default/ParseUtils.cpp @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2021 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 <ParseUtils.h> +#include <sstream> +#include <stdexcept> + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +int ParseUtils::tryParseInt(const std::string& s, int defaultVal) { + if (s.empty()) { + return defaultVal; + } else { + return std::stoi(s); + } +} + +float ParseUtils::tryParsefloat(const std::string& s, float defaultVal) { + if (s.empty()) { + return defaultVal; + } else { + return std::stof(s); + } +} + +double ParseUtils::tryParseDouble(const std::string& s, double defaultVal) { + if (s.empty()) { + return defaultVal; + } else { + return std::stod(s); + } +} + +long ParseUtils::tryParseLong(const std::string& s, long defaultVal) { + if (s.empty()) { + return defaultVal; + } else { + return std::stol(s); + } +} + +long long ParseUtils::tryParseLongLong(const std::string& s, long long defaultVal) { + if (s.empty()) { + return defaultVal; + } else { + return std::stoll(s); + } +} + +void ParseUtils::splitStr(const std::string& line, const char& delimiter, + std::vector<std::string>& out) { + std::istringstream iss(line); + std::string item; + while (std::getline(iss, item, delimiter)) { + out.push_back(item); + } +} + +bool ParseUtils::isValidHeader(const std::unordered_map<std::string, int>& columnNameIdMapping) { + std::vector<std::string> requiredHeaderColumns = {"Raw", + "utcTimeMillis", + "TimeNanos", + "LeapSecond", + "TimeUncertaintyNanos", + "FullBiasNanos", + "BiasNanos", + "BiasUncertaintyNanos", + "DriftNanosPerSecond", + "DriftUncertaintyNanosPerSecond", + "HardwareClockDiscontinuityCount", + "Svid", + "TimeOffsetNanos", + "State", + "ReceivedSvTimeNanos", + "ReceivedSvTimeUncertaintyNanos", + "Cn0DbHz", + "PseudorangeRateMetersPerSecond", + "PseudorangeRateUncertaintyMetersPerSecond", + "AccumulatedDeltaRangeState", + "AccumulatedDeltaRangeMeters", + "AccumulatedDeltaRangeUncertaintyMeters", + "CarrierFrequencyHz", + "CarrierCycles", + "CarrierPhase", + "CarrierPhaseUncertainty", + "MultipathIndicator", + "SnrInDb", + "ConstellationType", + "AgcDb", + "BasebandCn0DbHz", + "FullInterSignalBiasNanos", + "FullInterSignalBiasUncertaintyNanos", + "SatelliteInterSignalBiasNanos", + "SatelliteInterSignalBiasUncertaintyNanos", + "CodeType", + "ChipsetElapsedRealtimeNanos"}; + + for (const auto& columnName : requiredHeaderColumns) { + if (columnNameIdMapping.find(columnName) == columnNameIdMapping.end()) { + ALOGE("Missing column %s in header.", columnName.c_str()); + return false; + } + } + + return true; +} + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android diff --git a/gnss/common/utils/default/include/Constants.h b/gnss/common/utils/default/include/Constants.h index 22afee1ad1..489413e21d 100644 --- a/gnss/common/utils/default/include/Constants.h +++ b/gnss/common/utils/default/include/Constants.h @@ -34,6 +34,19 @@ const float kGpsL5FreqHz = 1176.45 * 1e6; const float kGloG1FreqHz = 1602.0 * 1e6; const float kIrnssL5FreqHz = 1176.45 * 1e6; +// Location replay constants +constexpr char GNSS_PATH[] = "/dev/gnss0"; +constexpr char FIXED_LOCATION_PATH[] = "/dev/gnss1"; +constexpr int INPUT_BUFFER_SIZE = 256; +constexpr char CMD_GET_LOCATION[] = "CMD_GET_LOCATION"; +constexpr char CMD_GET_RAWMEASUREMENT[] = "CMD_GET_RAWMEASUREMENT"; +constexpr char LINE_SEPARATOR = '\n'; +constexpr char COMMA_SEPARATOR = ','; +constexpr char GPGA_RECORD_TAG[] = "$GPGGA"; +constexpr char GPRMC_RECORD_TAG[] = "$GPRMC"; +constexpr double TIMESTAMP_EPSILON = 0.001; +constexpr int MIN_COL_NUM = 13; + } // namespace common } // namespace gnss } // namespace hardware diff --git a/gnss/common/utils/default/include/DeviceFileReader.h b/gnss/common/utils/default/include/DeviceFileReader.h new file mode 100644 index 0000000000..c2a5c5f59b --- /dev/null +++ b/gnss/common/utils/default/include/DeviceFileReader.h @@ -0,0 +1,53 @@ + +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef android_hardware_gnss_common_default_DeviceFileReader_H_ +#define android_hardware_gnss_common_default_DeviceFileReader_H_ + +#include <log/log.h> +#include <mutex> +#include <string> +#include <unordered_map> +#include "Constants.h" +#include "GnssReplayUtils.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { +class DeviceFileReader { + public: + static DeviceFileReader& Instance() { + static DeviceFileReader reader; + return reader; + } + std::string getLocationData(); + std::string getGnssRawMeasurementData(); + void getDataFromDeviceFile(const std::string& command, int mMinIntervalMs); + + private: + DeviceFileReader(); + ~DeviceFileReader(); + std::unordered_map<std::string, std::string> data_; + std::string s_buffer_; + std::mutex mMutex; +}; +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_common_default_DeviceFileReader_H_
\ No newline at end of file diff --git a/gnss/common/utils/default/include/FixLocationParser.h b/gnss/common/utils/default/include/FixLocationParser.h new file mode 100644 index 0000000000..19748a9dd1 --- /dev/null +++ b/gnss/common/utils/default/include/FixLocationParser.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef android_hardware_gnss_common_default_FixLocationParser_H_ +#define android_hardware_gnss_common_default_FixLocationParser_H_ + +#include <android/hardware/gnss/2.0/IGnss.h> + +#include <utils/SystemClock.h> +#include <string> +#include <vector> + +#include <Constants.h> +#include <Utils.h> +#include <log/log.h> +#include "Constants.h" +#include "ParseUtils.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +struct FixLocationParser { + public: + static std::unique_ptr<V2_0::GnssLocation> getLocationFromInputStr(const std::string& inputStr); +}; + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_common_default_FixLocationParser_H_ diff --git a/gnss/common/utils/default/include/GnssRawMeasurementParser.h b/gnss/common/utils/default/include/GnssRawMeasurementParser.h new file mode 100644 index 0000000000..7d6b4efdd1 --- /dev/null +++ b/gnss/common/utils/default/include/GnssRawMeasurementParser.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef android_hardware_gnss_common_default_GnssRawMeasurementParser_H_ +#define android_hardware_gnss_common_default_GnssRawMeasurementParser_H_ + +#include <aidl/android/hardware/gnss/BnGnss.h> +#include <log/log.h> +#include <utils/SystemClock.h> +#include <string> +#include <unordered_map> + +#include "Constants.h" +#include "ParseUtils.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +struct GnssRawMeasurementParser { + static std::unique_ptr<aidl::android::hardware::gnss::GnssData> getMeasurementFromStrs( + std::string& rawMeasurementStr); + static int getClockFlags(const std::vector<std::string>& rawMeasurementRecordValues, + const std::unordered_map<std::string, int>& columnNameIdMapping); + static int getElapsedRealtimeFlags( + const std::vector<std::string>& rawMeasurementRecordValues, + const std::unordered_map<std::string, int>& columnNameIdMapping); + static int getRawMeasurementFlags( + const std::vector<std::string>& rawMeasurementRecordValues, + const std::unordered_map<std::string, int>& columnNameIdMapping); + static std::unordered_map<std::string, int> getColumnIdNameMappingFromHeader( + const std::string& header); + static aidl::android::hardware::gnss::GnssConstellationType getGnssConstellationType( + int constellationType); +}; + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_common_default_GnssRawMeasurementParser_H_
\ No newline at end of file diff --git a/gnss/common/utils/default/include/GnssReplayUtils.h b/gnss/common/utils/default/include/GnssReplayUtils.h new file mode 100644 index 0000000000..d1bbed4b41 --- /dev/null +++ b/gnss/common/utils/default/include/GnssReplayUtils.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef android_hardware_gnss_common_GnssReplayUtils_H_ +#define android_hardware_gnss_common_GnssReplayUtils_H_ + +#include <cutils/properties.h> +#include <errno.h> +#include <fcntl.h> +#include <log/log.h> +#include <sys/epoll.h> +#include <sys/stat.h> +#include <chrono> +#include <string> +#include <thread> + +#include "Constants.h" + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +struct ReplayUtils { + static std::string getGnssPath(); + + static std::string getFixedLocationPath(); + + static std::string getDataFromDeviceFile(const std::string& command, int mMinIntervalMs); + + static bool hasGnssDeviceFile(); + + static bool hasFixedLocationDeviceFile(); + + static bool isGnssRawMeasurement(const std::string& inputStr); + + static bool isNMEA(const std::string& inputStr); +}; + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_common_GnssReplayUtils_H_ diff --git a/gnss/common/utils/default/include/NmeaFixInfo.h b/gnss/common/utils/default/include/NmeaFixInfo.h index c96eecea00..5c27045316 100644 --- a/gnss/common/utils/default/include/NmeaFixInfo.h +++ b/gnss/common/utils/default/include/NmeaFixInfo.h @@ -27,13 +27,6 @@ namespace hardware { namespace gnss { namespace common { -constexpr char GPGA_RECORD_TAG[] = "$GPGGA"; -constexpr char GPRMC_RECORD_TAG[] = "$GPRMC"; -constexpr char LINE_SEPARATOR = '\n'; -constexpr char COMMA_SEPARATOR = ','; -constexpr double TIMESTAMP_EPSILON = 0.001; -constexpr int MIN_COL_NUM = 13; - /** Helper class to parse and store the GNSS fix details information. */ class NmeaFixInfo { private: diff --git a/gnss/common/utils/default/include/ParseUtils.h b/gnss/common/utils/default/include/ParseUtils.h new file mode 100644 index 0000000000..3a5631342e --- /dev/null +++ b/gnss/common/utils/default/include/ParseUtils.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef android_hardware_gnss_common_default_ParseUtils_H_ +#define android_hardware_gnss_common_default_ParseUtils_H_ + +#include <log/log.h> +#include <string> +#include <unordered_map> +#include <vector> + +namespace android { +namespace hardware { +namespace gnss { +namespace common { + +struct ParseUtils { + static int tryParseInt(const std::string& s, int defaultVal = 0); + static float tryParsefloat(const std::string& s, float defaultVal = 0.0); + static double tryParseDouble(const std::string& s, double defaultVal = 0.0); + static long tryParseLong(const std::string& s, long defaultVal = 0); + static long long tryParseLongLong(const std::string& s, long long defaultVal = 0); + static void splitStr(const std::string& line, const char& delimiter, + std::vector<std::string>& out); + static bool isValidHeader(const std::unordered_map<std::string, int>& columnNameIdMapping); +}; + +} // namespace common +} // namespace gnss +} // namespace hardware +} // namespace android + +#endif // android_hardware_gnss_common_default_ParseUtils_H_
\ No newline at end of file diff --git a/gnss/common/utils/default/include/v2_1/GnssTemplate.h b/gnss/common/utils/default/include/v2_1/GnssTemplate.h index 131af24fbe..473e587762 100644 --- a/gnss/common/utils/default/include/v2_1/GnssTemplate.h +++ b/gnss/common/utils/default/include/v2_1/GnssTemplate.h @@ -30,13 +30,15 @@ #include <cutils/properties.h> +#include "DeviceFileReader.h" +#include "FixLocationParser.h" #include "GnssAntennaInfo.h" #include "GnssConfiguration.h" #include "GnssDebug.h" #include "GnssMeasurement.h" #include "GnssMeasurementCorrections.h" +#include "GnssReplayUtils.h" #include "MockLocation.h" -#include "NmeaFixInfo.h" #include "Utils.h" namespace android::hardware::gnss::common::implementation { @@ -159,53 +161,13 @@ GnssTemplate<T_IGnss>::~GnssTemplate() { template <class T_IGnss> std::unique_ptr<V2_0::GnssLocation> GnssTemplate<T_IGnss>::getLocationFromHW() { - char inputBuffer[INPUT_BUFFER_SIZE]; - if (!mHardwareModeChecked) { - // default using gnss0 - const char * gnss_dev_path = GNSS_PATH; - char devname_value[PROPERTY_VALUE_MAX] = ""; - if (property_get("debug.location.gnss.devname", devname_value, NULL) > 0) { - gnss_dev_path = devname_value; - ALOGD("using %s instead of the default %s", gnss_dev_path, GNSS_PATH); - } - - mGnssFd = open(gnss_dev_path, O_RDWR | O_NONBLOCK); - if (mGnssFd == -1) { - ALOGW("Failed to open %s errno: %d", gnss_dev_path, errno); - } - mHardwareModeChecked = true; - } - - if (mGnssFd == -1) { - return nullptr; - } - - int bytes_write = write(mGnssFd, CMD_GET_LOCATION, strlen(CMD_GET_LOCATION)); - if (bytes_write <= 0) { + mHardwareModeChecked = true; + if (!ReplayUtils::hasFixedLocationDeviceFile()) { return nullptr; } - - struct epoll_event ev, events[1]; - ev.data.fd = mGnssFd; - ev.events = EPOLLIN; - int epoll_fd = epoll_create1(0); - epoll_ctl(epoll_fd, EPOLL_CTL_ADD, mGnssFd, &ev); - int bytes_read = -1; - std::string inputStr = ""; - int epoll_ret = epoll_wait(epoll_fd, events, 1, mMinIntervalMs); - - if (epoll_ret == -1) { - return nullptr; - } - while (true) { - memset(inputBuffer, 0, INPUT_BUFFER_SIZE); - bytes_read = read(mGnssFd, &inputBuffer, INPUT_BUFFER_SIZE); - if (bytes_read <= 0) { - break; - } - inputStr += std::string(inputBuffer, bytes_read); - } - return NmeaFixInfo::getLocationFromInputStr(inputStr); + std::string inputStr = + ::android::hardware::gnss::common::DeviceFileReader::Instance().getLocationData(); + return FixLocationParser::getLocationFromInputStr(inputStr); } template <class T_IGnss> @@ -223,14 +185,8 @@ Return<bool> GnssTemplate<T_IGnss>::start() { this->reportSvStatus(svStatus); auto currentLocation = getLocationFromHW(); notePowerConsumption(); - if (mGnssFd != -1) { - // Only report location if the return from hardware is valid - // note that we can not merge these two "if" together, if didn't - // get location from hardware, we shouldn't report location, not - // report the "default" one. - if (currentLocation != nullptr) { - this->reportLocation(*currentLocation); - } + if (currentLocation != nullptr) { + this->reportLocation(*currentLocation); } else { if (sGnssCallback_2_1 != nullptr || sGnssCallback_2_0 != nullptr) { const auto location = Utils::getMockLocationV2_0(); diff --git a/graphics/composer/2.1/utils/vts/GraphicsComposerCallback.cpp b/graphics/composer/2.1/utils/vts/GraphicsComposerCallback.cpp index 1ead138efc..ccbc5b1292 100644 --- a/graphics/composer/2.1/utils/vts/GraphicsComposerCallback.cpp +++ b/graphics/composer/2.1/utils/vts/GraphicsComposerCallback.cpp @@ -30,7 +30,7 @@ void GraphicsComposerCallback::setVsyncAllowed(bool allowed) { std::vector<Display> GraphicsComposerCallback::getDisplays() const { std::lock_guard<std::mutex> lock(mMutex); - return std::vector<Display>(mDisplays.begin(), mDisplays.end()); + return mDisplays; } int GraphicsComposerCallback::getInvalidHotplugCount() const { @@ -51,12 +51,17 @@ int GraphicsComposerCallback::getInvalidVsyncCount() const { Return<void> GraphicsComposerCallback::onHotplug(Display display, Connection connection) { std::lock_guard<std::mutex> lock(mMutex); + auto it = std::find(mDisplays.begin(), mDisplays.end(), display); if (connection == Connection::CONNECTED) { - if (!mDisplays.insert(display).second) { + if (it == mDisplays.end()) { + mDisplays.push_back(display); + } else { mInvalidHotplugCount++; } } else if (connection == Connection::DISCONNECTED) { - if (!mDisplays.erase(display)) { + if (it != mDisplays.end()) { + mDisplays.erase(it); + } else { mInvalidHotplugCount++; } } @@ -67,7 +72,8 @@ Return<void> GraphicsComposerCallback::onHotplug(Display display, Connection con Return<void> GraphicsComposerCallback::onRefresh(Display display) { std::lock_guard<std::mutex> lock(mMutex); - if (mDisplays.count(display) == 0) { + auto it = std::find(mDisplays.begin(), mDisplays.end(), display); + if (it == mDisplays.end()) { mInvalidRefreshCount++; } @@ -77,7 +83,8 @@ Return<void> GraphicsComposerCallback::onRefresh(Display display) { Return<void> GraphicsComposerCallback::onVsync(Display display, int64_t) { std::lock_guard<std::mutex> lock(mMutex); - if (!mVsyncAllowed || mDisplays.count(display) == 0) { + auto it = std::find(mDisplays.begin(), mDisplays.end(), display); + if (!mVsyncAllowed || it == mDisplays.end()) { mInvalidVsyncCount++; } diff --git a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/GraphicsComposerCallback.h b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/GraphicsComposerCallback.h index e3c348f7de..da640528ab 100644 --- a/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/GraphicsComposerCallback.h +++ b/graphics/composer/2.1/utils/vts/include/composer-vts/2.1/GraphicsComposerCallback.h @@ -19,7 +19,7 @@ #include <android/hardware/graphics/composer/2.1/IComposerCallback.h> #include <mutex> -#include <unordered_set> +#include <vector> namespace android { namespace hardware { @@ -48,7 +48,7 @@ class GraphicsComposerCallback : public IComposerCallback { mutable std::mutex mMutex; // the set of all currently connected displays - std::unordered_set<Display> mDisplays; + std::vector<Display> mDisplays; // true only when vsync is enabled bool mVsyncAllowed = true; diff --git a/graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp b/graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp index c9366a8495..51e1ab75f8 100644 --- a/graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp +++ b/graphics/composer/2.4/utils/vts/GraphicsComposerCallback.cpp @@ -25,7 +25,7 @@ void GraphicsComposerCallback::setVsyncAllowed(bool allowed) { std::vector<Display> GraphicsComposerCallback::getDisplays() const { std::lock_guard<std::mutex> lock(mMutex); - return std::vector<Display>(mDisplays.begin(), mDisplays.end()); + return mDisplays; } int32_t GraphicsComposerCallback::getInvalidHotplugCount() const { @@ -71,12 +71,17 @@ GraphicsComposerCallback::takeLastVsyncPeriodChangeTimeline() { Return<void> GraphicsComposerCallback::onHotplug(Display display, Connection connection) { std::lock_guard<std::mutex> lock(mMutex); + auto it = std::find(mDisplays.begin(), mDisplays.end(), display); if (connection == Connection::CONNECTED) { - if (!mDisplays.insert(display).second) { + if (it == mDisplays.end()) { + mDisplays.push_back(display); + } else { mInvalidHotplugCount++; } } else if (connection == Connection::DISCONNECTED) { - if (!mDisplays.erase(display)) { + if (it != mDisplays.end()) { + mDisplays.erase(it); + } else { mInvalidHotplugCount++; } } @@ -87,7 +92,8 @@ Return<void> GraphicsComposerCallback::onHotplug(Display display, Connection con Return<void> GraphicsComposerCallback::onRefresh(Display display) { std::lock_guard<std::mutex> lock(mMutex); - if (mDisplays.count(display) == 0) { + auto it = std::find(mDisplays.begin(), mDisplays.end(), display); + if (it == mDisplays.end()) { mInvalidRefreshCount++; } @@ -106,7 +112,8 @@ Return<void> GraphicsComposerCallback::onVsync(Display, int64_t) { Return<void> GraphicsComposerCallback::onVsync_2_4(Display display, int64_t, VsyncPeriodNanos) { std::lock_guard<std::mutex> lock(mMutex); - if (!mVsyncAllowed || mDisplays.count(display) == 0) { + auto it = std::find(mDisplays.begin(), mDisplays.end(), display); + if (!mVsyncAllowed || it == mDisplays.end()) { mInvalidVsync_2_4Count++; } @@ -117,7 +124,8 @@ Return<void> GraphicsComposerCallback::onVsyncPeriodTimingChanged( Display display, const VsyncPeriodChangeTimeline& updatedTimeline) { std::lock_guard<std::mutex> lock(mMutex); - if (mDisplays.count(display) == 0) { + auto it = std::find(mDisplays.begin(), mDisplays.end(), display); + if (it == mDisplays.end()) { mInvalidVsyncPeriodChangeCount++; } @@ -134,4 +142,4 @@ Return<void> GraphicsComposerCallback::onSeamlessPossible(Display) { return Void(); } -} // namespace android::hardware::graphics::composer::V2_4::vts
\ No newline at end of file +} // namespace android::hardware::graphics::composer::V2_4::vts diff --git a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h index f4e23ae1fd..c03070b10c 100644 --- a/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h +++ b/graphics/composer/2.4/utils/vts/include/composer-vts/2.4/GraphicsComposerCallback.h @@ -18,7 +18,7 @@ #include <android/hardware/graphics/composer/2.4/IComposerCallback.h> #include <mutex> -#include <unordered_set> +#include <vector> namespace android::hardware::graphics::composer::V2_4::vts { @@ -56,7 +56,7 @@ class GraphicsComposerCallback : public IComposerCallback { mutable std::mutex mMutex; // the set of all currently connected displays - std::unordered_set<Display> mDisplays; + std::vector<Display> mDisplays; // true only when vsync is enabled bool mVsyncAllowed = true; diff --git a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp index 5aceda721e..b071f71e85 100644 --- a/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp +++ b/graphics/composer/2.4/vts/functional/VtsHalGraphicsComposerV2_4TargetTest.cpp @@ -19,8 +19,6 @@ #include <algorithm> #include <regex> #include <thread> -#include <unordered_map> -#include <utility> #include <android-base/logging.h> #include <android-base/properties.h> @@ -317,59 +315,6 @@ TEST_P(GraphicsComposerHidlTest, GetDisplayAttribute_2_4) { } } -TEST_P(GraphicsComposerHidlTest, GetDisplayAttribute_2_4_ConfigsInAGroupDifferOnlyByVsyncPeriod) { - struct Resolution { - int32_t width, height; - }; - struct Dpi { - int32_t x, y; - }; - for (const auto& display : mDisplays) { - std::vector<Config> configs = mComposerClient->getDisplayConfigs(display.get()); - std::unordered_map<int32_t, Resolution> configGroupToResolutionMap; - std::unordered_map<int32_t, Dpi> configGroupToDpiMap; - for (auto config : configs) { - const auto configGroup = mComposerClient->getDisplayAttribute_2_4( - display.get(), config, IComposerClient::Attribute::CONFIG_GROUP); - const auto width = mComposerClient->getDisplayAttribute_2_4( - display.get(), config, IComposerClient::Attribute::WIDTH); - const auto height = mComposerClient->getDisplayAttribute_2_4( - display.get(), config, IComposerClient::Attribute::HEIGHT); - if (configGroupToResolutionMap.find(configGroup) == configGroupToResolutionMap.end()) { - configGroupToResolutionMap[configGroup] = {width, height}; - } - EXPECT_EQ(configGroupToResolutionMap[configGroup].width, width); - EXPECT_EQ(configGroupToResolutionMap[configGroup].height, height); - - int32_t dpiX = -1; - mComposerClient->getRaw()->getDisplayAttribute_2_4( - display.get(), config, IComposerClient::Attribute::DPI_X, - [&](const auto& tmpError, const auto& value) { - if (tmpError == Error::NONE) { - dpiX = value; - } - }); - int32_t dpiY = -1; - mComposerClient->getRaw()->getDisplayAttribute_2_4( - display.get(), config, IComposerClient::Attribute::DPI_Y, - [&](const auto& tmpError, const auto& value) { - if (tmpError == Error::NONE) { - dpiY = value; - } - }); - if (dpiX == -1 && dpiY == -1) { - continue; - } - - if (configGroupToDpiMap.find(configGroup) == configGroupToDpiMap.end()) { - configGroupToDpiMap[configGroup] = {dpiX, dpiY}; - } - EXPECT_EQ(configGroupToDpiMap[configGroup].x, dpiX); - EXPECT_EQ(configGroupToDpiMap[configGroup].y, dpiY); - } - } -} - TEST_P(GraphicsComposerHidlTest, getDisplayVsyncPeriod_BadDisplay) { VsyncPeriodNanos vsyncPeriodNanos; EXPECT_EQ(Error::BAD_DISPLAY, diff --git a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp index f8f5cffd73..4549f51060 100644 --- a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp +++ b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp @@ -32,23 +32,17 @@ TEST_P(RadioHidlTest_v1_6, setAllowedNetworkTypesBitmap) { EXPECT_EQ(std::cv_status::no_timeout, wait()); EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type); EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial); - - if (getRadioHalCapabilities()) { - ASSERT_TRUE(CheckAnyOfErrors( - radioRsp_v1_6->rspInfo.error, - {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED})); - } else { - ASSERT_TRUE(CheckAnyOfErrors( - radioRsp_v1_6->rspInfo.error, - {::android::hardware::radio::V1_6::RadioError::NONE, - ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE, - ::android::hardware::radio::V1_6::RadioError::OPERATION_NOT_ALLOWED, - ::android::hardware::radio::V1_6::RadioError::MODE_NOT_SUPPORTED, - ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR, - ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS, - ::android::hardware::radio::V1_6::RadioError::MODEM_ERR, - ::android::hardware::radio::V1_6::RadioError::NO_RESOURCES})); - } + ASSERT_TRUE( + CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error, + {::android::hardware::radio::V1_6::RadioError::NONE, + ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE, + ::android::hardware::radio::V1_6::RadioError::OPERATION_NOT_ALLOWED, + ::android::hardware::radio::V1_6::RadioError::MODE_NOT_SUPPORTED, + ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR, + ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS, + ::android::hardware::radio::V1_6::RadioError::MODEM_ERR, + ::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED, + ::android::hardware::radio::V1_6::RadioError::NO_RESOURCES})); } /* @@ -74,23 +68,17 @@ TEST_P(RadioHidlTest_v1_6, getAllowedNetworkTypesBitmap) { EXPECT_EQ(std::cv_status::no_timeout, wait()); EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_6->rspInfo.type); EXPECT_EQ(serial, radioRsp_v1_6->rspInfo.serial); - - if (getRadioHalCapabilities()) { - ASSERT_TRUE(CheckAnyOfErrors( - radioRsp_v1_6->rspInfo.error, - {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED})); - } else { - ASSERT_TRUE(CheckAnyOfErrors( - radioRsp_v1_6->rspInfo.error, - {::android::hardware::radio::V1_6::RadioError::NONE, - ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE, - ::android::hardware::radio::V1_6::RadioError::OPERATION_NOT_ALLOWED, - ::android::hardware::radio::V1_6::RadioError::MODE_NOT_SUPPORTED, - ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR, - ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS, - ::android::hardware::radio::V1_6::RadioError::MODEM_ERR, - ::android::hardware::radio::V1_6::RadioError::NO_RESOURCES})); - } + ASSERT_TRUE(CheckAnyOfErrors( + radioRsp_v1_6->rspInfo.error, + {::android::hardware::radio::V1_6::RadioError::NONE, + ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE, + ::android::hardware::radio::V1_6::RadioError::OPERATION_NOT_ALLOWED, + ::android::hardware::radio::V1_6::RadioError::MODE_NOT_SUPPORTED, + ::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR, + ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS, + ::android::hardware::radio::V1_6::RadioError::MODEM_ERR, + ::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED, + ::android::hardware::radio::V1_6::RadioError::NO_RESOURCES})); } } @@ -515,7 +503,8 @@ TEST_P(RadioHidlTest_v1_6, setDataThrottling) { if (getRadioHalCapabilities()) { ASSERT_TRUE(CheckAnyOfErrors( radioRsp_v1_6->rspInfo.error, - {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED})); + {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED, + ::android::hardware::radio::V1_6::RadioError::NONE})); } else { ASSERT_TRUE(CheckAnyOfErrors( radioRsp_v1_6->rspInfo.error, @@ -537,7 +526,8 @@ TEST_P(RadioHidlTest_v1_6, setDataThrottling) { if (getRadioHalCapabilities()) { ASSERT_TRUE(CheckAnyOfErrors( radioRsp_v1_6->rspInfo.error, - {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED})); + {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED, + ::android::hardware::radio::V1_6::RadioError::NONE})); } else { ASSERT_TRUE(CheckAnyOfErrors( radioRsp_v1_6->rspInfo.error, @@ -559,7 +549,8 @@ TEST_P(RadioHidlTest_v1_6, setDataThrottling) { if (getRadioHalCapabilities()) { ASSERT_TRUE(CheckAnyOfErrors( radioRsp_v1_6->rspInfo.error, - {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED})); + {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED, + ::android::hardware::radio::V1_6::RadioError::NONE})); } else { ASSERT_TRUE(CheckAnyOfErrors( radioRsp_v1_6->rspInfo.error, @@ -580,7 +571,8 @@ TEST_P(RadioHidlTest_v1_6, setDataThrottling) { if (getRadioHalCapabilities()) { ASSERT_TRUE(CheckAnyOfErrors( radioRsp_v1_6->rspInfo.error, - {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED})); + {::android::hardware::radio::V1_6::RadioError::REQUEST_NOT_SUPPORTED, + ::android::hardware::radio::V1_6::RadioError::NONE})); } else { ASSERT_TRUE(CheckAnyOfErrors( radioRsp_v1_6->rspInfo.error, @@ -609,12 +601,16 @@ TEST_P(RadioHidlTest_v1_6, setSimCardPower_1_6) { ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS, ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE})); + // Give some time for modem to fully power up the SIM card + sleep(MODEM_SET_SIM_POWER_DELAY_IN_SECONDS); + // setSimCardPower_1_6 does not return until the request is handled, and should not trigger // CardState::ABSENT when turning off power if (radioRsp_v1_6->rspInfo.error == ::android::hardware::radio::V1_6::RadioError::NONE) { /* Wait some time for setting sim power down and then verify it */ updateSimCardStatus(); - EXPECT_EQ(CardState::PRESENT, cardStatus.base.base.base.cardState); + // We cannot assert the consistency of CardState here due to b/203031664 + // EXPECT_EQ(CardState::PRESENT, cardStatus.base.base.base.cardState); // applications should be an empty vector of AppStatus EXPECT_EQ(0, cardStatus.applications.size()); } @@ -631,6 +627,9 @@ TEST_P(RadioHidlTest_v1_6, setSimCardPower_1_6) { ::android::hardware::radio::V1_6::RadioError::INVALID_ARGUMENTS, ::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE})); + // Give some time for modem to fully power up the SIM card + sleep(MODEM_SET_SIM_POWER_DELAY_IN_SECONDS); + // setSimCardPower_1_6 does not return until the request is handled. Just verify that we still // have CardState::PRESENT after turning the power back on if (radioRsp_v1_6->rspInfo.error == ::android::hardware::radio::V1_6::RadioError::NONE) { @@ -646,6 +645,10 @@ TEST_P(RadioHidlTest_v1_6, emergencyDial_1_6) { if (!deviceSupportsFeature(FEATURE_VOICE_CALL)) { ALOGI("Skipping emergencyDial because voice call is not supported in device"); return; + } else if (!deviceSupportsFeature(FEATURE_TELEPHONY_GSM) && + !deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) { + ALOGI("Skipping emergencyDial because gsm/cdma radio is not supported in device"); + return; } else { ALOGI("Running emergencyDial because voice call is supported in device"); } @@ -700,6 +703,10 @@ TEST_P(RadioHidlTest_v1_6, emergencyDial_1_6_withServices) { if (!deviceSupportsFeature(FEATURE_VOICE_CALL)) { ALOGI("Skipping emergencyDial because voice call is not supported in device"); return; + } else if (!deviceSupportsFeature(FEATURE_TELEPHONY_GSM) && + !deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) { + ALOGI("Skipping emergencyDial because gsm/cdma radio is not supported in device"); + return; } else { ALOGI("Running emergencyDial because voice call is supported in device"); } @@ -753,6 +760,10 @@ TEST_P(RadioHidlTest_v1_6, emergencyDial_1_6_withEmergencyRouting) { if (!deviceSupportsFeature(FEATURE_VOICE_CALL)) { ALOGI("Skipping emergencyDial because voice call is not supported in device"); return; + } else if (!deviceSupportsFeature(FEATURE_TELEPHONY_GSM) && + !deviceSupportsFeature(FEATURE_TELEPHONY_CDMA)) { + ALOGI("Skipping emergencyDial because gsm/cdma radio is not supported in device"); + return; } else { ALOGI("Running emergencyDial because voice call is supported in device"); } diff --git a/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h b/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h index 54c297719f..f0418652fd 100644 --- a/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h +++ b/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h @@ -47,6 +47,7 @@ using ::android::hardware::Void; #define MODEM_EMERGENCY_CALL_ESTABLISH_TIME 3 #define MODEM_EMERGENCY_CALL_DISCONNECT_TIME 3 +#define MODEM_SET_SIM_POWER_DELAY_IN_SECONDS 2 #define RADIO_SERVICE_SLOT1_NAME "slot1" // HAL instance name for SIM slot 1 or single SIM device #define RADIO_SERVICE_SLOT2_NAME "slot2" // HAL instance name for SIM slot 2 on dual SIM device diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp index 26ed34427c..64550eff2d 100644 --- a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp +++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp @@ -50,7 +50,7 @@ TEST_P(AttestKeyTest, AllRsaSizes) { vector<KeyCharacteristics> attest_key_characteristics; vector<Certificate> attest_key_cert_chain; ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() - .RsaSigningKey(size, 65537) + .RsaKey(size, 65537) .AttestKey() .SetDefaultValidity(), {} /* attestation signing key */, &attest_key.keyBlob, @@ -200,7 +200,7 @@ TEST_P(AttestKeyTest, RsaAttestedAttestKeys) { vector<Certificate> attest_key_cert_chain; ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() - .RsaSigningKey(2048, 65537) + .RsaKey(2048, 65537) .AttestKey() .AttestationChallenge(challenge) .AttestationApplicationId(app_id) @@ -299,7 +299,7 @@ TEST_P(AttestKeyTest, RsaAttestKeyChaining) { EXPECT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() - .RsaSigningKey(2048, 65537) + .RsaKey(2048, 65537) .AttestKey() .AttestationChallenge("foo") .AttestationApplicationId("bar") @@ -371,7 +371,7 @@ TEST_P(AttestKeyTest, EcAttestKeyChaining) { EXPECT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() - .EcdsaSigningKey(EcCurve::P_256) + .EcdsaKey(EcCurve::P_256) .AttestKey() .AttestationChallenge("foo") .AttestationApplicationId("bar") @@ -446,7 +446,7 @@ TEST_P(AttestKeyTest, AlternateAttestKeyChaining) { if ((i & 0x1) == 1) { EXPECT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() - .EcdsaSigningKey(EcCurve::P_256) + .EcdsaKey(EcCurve::P_256) .AttestKey() .AttestationChallenge("foo") .AttestationApplicationId("bar") @@ -459,7 +459,7 @@ TEST_P(AttestKeyTest, AlternateAttestKeyChaining) { } else { EXPECT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() - .RsaSigningKey(2048, 65537) + .RsaKey(2048, 65537) .AttestKey() .AttestationChallenge("foo") .AttestationApplicationId("bar") @@ -509,7 +509,7 @@ TEST_P(AttestKeyTest, MissingChallenge) { vector<KeyCharacteristics> attest_key_characteristics; vector<Certificate> attest_key_cert_chain; ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() - .RsaSigningKey(size, 65537) + .RsaKey(size, 65537) .AttestKey() .SetDefaultValidity(), {} /* attestation signing key */, &attest_key.keyBlob, @@ -555,12 +555,12 @@ TEST_P(AttestKeyTest, AllEcCurves) { AttestationKey attest_key; vector<KeyCharacteristics> attest_key_characteristics; vector<Certificate> attest_key_cert_chain; - ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() - .EcdsaSigningKey(curve) - .AttestKey() - .SetDefaultValidity(), - {} /* attestation signing key */, &attest_key.keyBlob, - &attest_key_characteristics, &attest_key_cert_chain)); + ASSERT_EQ( + ErrorCode::OK, + GenerateKey( + AuthorizationSetBuilder().EcdsaKey(curve).AttestKey().SetDefaultValidity(), + {} /* attestation signing key */, &attest_key.keyBlob, + &attest_key_characteristics, &attest_key_cert_chain)); ASSERT_GT(attest_key_cert_chain.size(), 0); EXPECT_EQ(attest_key_cert_chain.size(), 1); @@ -671,7 +671,7 @@ TEST_P(AttestKeyTest, EcdsaAttestationID) { vector<KeyCharacteristics> attest_key_characteristics; vector<Certificate> attest_key_cert_chain; ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() - .EcdsaSigningKey(EcCurve::P_256) + .EcdsaKey(EcCurve::P_256) .AttestKey() .SetDefaultValidity(), {} /* attestation signing key */, &attest_key.keyBlob, @@ -735,7 +735,7 @@ TEST_P(AttestKeyTest, EcdsaAttestationMismatchID) { vector<KeyCharacteristics> attest_key_characteristics; vector<Certificate> attest_key_cert_chain; ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder() - .EcdsaSigningKey(EcCurve::P_256) + .EcdsaKey(EcCurve::P_256) .AttestKey() .SetDefaultValidity(), {} /* attestation signing key */, &attest_key.keyBlob, diff --git a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp index d7abf0790c..79716b1354 100644 --- a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp +++ b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp @@ -76,6 +76,7 @@ TEST_P(DeviceUniqueAttestationTest, RsaNonStrongBoxUnimplemented) { .Digest(Digest::SHA_2_256) .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN) .Authorization(TAG_INCLUDE_UNIQUE_ID) + .Authorization(TAG_CREATION_DATETIME, 1619621648000) .AttestationChallenge("challenge") .AttestationApplicationId("foo") .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION), @@ -102,6 +103,7 @@ TEST_P(DeviceUniqueAttestationTest, EcdsaNonStrongBoxUnimplemented) { .EcdsaSigningKey(EcCurve::P_256) .Digest(Digest::SHA_2_256) .Authorization(TAG_INCLUDE_UNIQUE_ID) + .Authorization(TAG_CREATION_DATETIME, 1619621648000) .AttestationChallenge("challenge") .AttestationApplicationId("foo") .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION), @@ -129,6 +131,7 @@ TEST_P(DeviceUniqueAttestationTest, RsaDeviceUniqueAttestation) { .Digest(Digest::SHA_2_256) .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN) .Authorization(TAG_INCLUDE_UNIQUE_ID) + .Authorization(TAG_CREATION_DATETIME, 1619621648000) .AttestationChallenge("challenge") .AttestationApplicationId("foo") .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION), @@ -184,6 +187,7 @@ TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestation) { .EcdsaSigningKey(EcCurve::P_256) .Digest(Digest::SHA_2_256) .Authorization(TAG_INCLUDE_UNIQUE_ID) + .Authorization(TAG_CREATION_DATETIME, 1619621648000) .AttestationChallenge("challenge") .AttestationApplicationId("foo") .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION), @@ -242,14 +246,16 @@ TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestationID) { for (const KeyParameter& tag : attestation_id_tags) { SCOPED_TRACE(testing::Message() << "+tag-" << tag); - AuthorizationSetBuilder builder = AuthorizationSetBuilder() - .Authorization(TAG_NO_AUTH_REQUIRED) - .EcdsaSigningKey(EcCurve::P_256) - .Digest(Digest::SHA_2_256) - .Authorization(TAG_INCLUDE_UNIQUE_ID) - .AttestationChallenge("challenge") - .AttestationApplicationId("foo") - .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION); + AuthorizationSetBuilder builder = + AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(EcCurve::P_256) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_INCLUDE_UNIQUE_ID) + .Authorization(TAG_CREATION_DATETIME, 1619621648000) + .AttestationChallenge("challenge") + .AttestationApplicationId("foo") + .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION); builder.push_back(tag); auto result = GenerateKey(builder, &key_blob, &key_characteristics); @@ -310,14 +316,16 @@ TEST_P(DeviceUniqueAttestationTest, EcdsaDeviceUniqueAttestationMismatchID) { for (const KeyParameter& invalid_tag : attestation_id_tags) { SCOPED_TRACE(testing::Message() << "+tag-" << invalid_tag); - AuthorizationSetBuilder builder = AuthorizationSetBuilder() - .Authorization(TAG_NO_AUTH_REQUIRED) - .EcdsaSigningKey(EcCurve::P_256) - .Digest(Digest::SHA_2_256) - .Authorization(TAG_INCLUDE_UNIQUE_ID) - .AttestationChallenge("challenge") - .AttestationApplicationId("foo") - .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION); + AuthorizationSetBuilder builder = + AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .EcdsaSigningKey(EcCurve::P_256) + .Digest(Digest::SHA_2_256) + .Authorization(TAG_INCLUDE_UNIQUE_ID) + .Authorization(TAG_CREATION_DATETIME, 1619621648000) + .AttestationChallenge("challenge") + .AttestationApplicationId("foo") + .Authorization(TAG_DEVICE_UNIQUE_ATTESTATION); // Add the tag that doesn't match the local device's real ID. builder.push_back(invalid_tag); auto result = GenerateKey(builder, &key_blob, &key_characteristics); diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp index 20324117b9..8e35c91b66 100644 --- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp +++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp @@ -1298,7 +1298,8 @@ bool verify_attestation_record(const string& challenge, // AuthorizationSet expected_sw_enforced, // AuthorizationSet expected_hw_enforced, // SecurityLevel security_level, - const vector<uint8_t>& attestation_cert) { + const vector<uint8_t>& attestation_cert, + vector<uint8_t>* unique_id) { X509_Ptr cert(parse_cert_blob(attestation_cert)); EXPECT_TRUE(!!cert.get()); if (!cert.get()) return false; @@ -1458,6 +1459,10 @@ bool verify_attestation_record(const string& challenge, // expected_hw_enforced.Sort(); EXPECT_EQ(filtered_tags(expected_hw_enforced), filtered_tags(att_hw_enforced)); + if (unique_id != nullptr) { + *unique_id = att_unique_id; + } + return true; } diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h index ec3fcf6a3e..7b3b9d4b4b 100644 --- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h +++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h @@ -338,7 +338,8 @@ bool verify_attestation_record(const string& challenge, // AuthorizationSet expected_sw_enforced, // AuthorizationSet expected_hw_enforced, // SecurityLevel security_level, - const vector<uint8_t>& attestation_cert); + const vector<uint8_t>& attestation_cert, + vector<uint8_t>* unique_id = nullptr); string bin2hex(const vector<uint8_t>& data); X509_Ptr parse_cert_blob(const vector<uint8_t>& blob); diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp index 2a0ee7fd3e..4d7f1b8eec 100644 --- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp +++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp @@ -1550,6 +1550,102 @@ TEST_P(NewKeyGenerationTest, EcdsaAttestationTags) { } /* + * NewKeyGenerationTest.EcdsaAttestationUniqueId + * + * Verifies that creation of an attested ECDSA key with a UNIQUE_ID included. + */ +TEST_P(NewKeyGenerationTest, EcdsaAttestationUniqueId) { + auto get_unique_id = [this](const std::string& app_id, uint64_t datetime, + vector<uint8_t>* unique_id, bool reset = false) { + auto challenge = "hello"; + auto subject = "cert subj 2"; + vector<uint8_t> subject_der(make_name_from_str(subject)); + uint64_t serial_int = 0x1010; + vector<uint8_t> serial_blob(build_serial_blob(serial_int)); + AuthorizationSetBuilder builder = + AuthorizationSetBuilder() + .Authorization(TAG_NO_AUTH_REQUIRED) + .Authorization(TAG_INCLUDE_UNIQUE_ID) + .EcdsaSigningKey(EcCurve::P_256) + .Digest(Digest::NONE) + .AttestationChallenge(challenge) + .Authorization(TAG_CERTIFICATE_SERIAL, serial_blob) + .Authorization(TAG_CERTIFICATE_SUBJECT, subject_der) + .AttestationApplicationId(app_id) + .Authorization(TAG_CREATION_DATETIME, datetime) + .SetDefaultValidity(); + if (reset) { + builder.Authorization(TAG_RESET_SINCE_ID_ROTATION); + } + + ASSERT_EQ(ErrorCode::OK, GenerateKey(builder)); + ASSERT_GT(key_blob_.size(), 0U); + + EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_)); + ASSERT_GT(cert_chain_.size(), 0); + verify_subject_and_serial(cert_chain_[0], serial_int, subject, /* self_signed = */ false); + + AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics_); + AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics_); + + // Check that the unique ID field in the extension is non-empty. + EXPECT_TRUE(verify_attestation_record(challenge, app_id, sw_enforced, hw_enforced, + SecLevel(), cert_chain_[0].encodedCertificate, + unique_id)); + EXPECT_GT(unique_id->size(), 0); + CheckedDeleteKey(); + }; + + // Generate unique ID + auto app_id = "foo"; + uint64_t cert_date = 1619621648000; // Wed Apr 28 14:54:08 2021 in ms since epoch + vector<uint8_t> unique_id; + get_unique_id(app_id, cert_date, &unique_id); + + // Generating a new key with the same parameters should give the same unique ID. + vector<uint8_t> unique_id2; + get_unique_id(app_id, cert_date, &unique_id2); + EXPECT_EQ(unique_id, unique_id2); + + // Generating a new key with a slightly different date should give the same unique ID. + uint64_t rounded_date = cert_date / 2592000000LLU; + uint64_t min_date = rounded_date * 2592000000LLU; + uint64_t max_date = ((rounded_date + 1) * 2592000000LLU) - 1; + + vector<uint8_t> unique_id3; + get_unique_id(app_id, min_date, &unique_id3); + EXPECT_EQ(unique_id, unique_id3); + + vector<uint8_t> unique_id4; + get_unique_id(app_id, max_date, &unique_id4); + EXPECT_EQ(unique_id, unique_id4); + + // A different attestation application ID should yield a different unique ID. + auto app_id2 = "different_foo"; + vector<uint8_t> unique_id5; + get_unique_id(app_id2, cert_date, &unique_id5); + EXPECT_NE(unique_id, unique_id5); + + // A radically different date should yield a different unique ID. + vector<uint8_t> unique_id6; + get_unique_id(app_id, 1611621648000, &unique_id6); + EXPECT_NE(unique_id, unique_id6); + + vector<uint8_t> unique_id7; + get_unique_id(app_id, max_date + 1, &unique_id7); + EXPECT_NE(unique_id, unique_id7); + + vector<uint8_t> unique_id8; + get_unique_id(app_id, min_date - 1, &unique_id8); + EXPECT_NE(unique_id, unique_id8); + + // Marking RESET_SINCE_ID_ROTATION should give a different unique ID. + vector<uint8_t> unique_id9; + get_unique_id(app_id, cert_date, &unique_id9, /* reset_id = */ true); + EXPECT_NE(unique_id, unique_id9); +} + +/* * NewKeyGenerationTest.EcdsaAttestationTagNoApplicationId * * Verifies that creation of an attested ECDSA key does not include APPLICATION_ID. diff --git a/wifi/1.0/vts/functional/Android.bp b/wifi/1.0/vts/functional/Android.bp index e4948b4cc2..6c0ebf7637 100644 --- a/wifi/1.0/vts/functional/Android.bp +++ b/wifi/1.0/vts/functional/Android.bp @@ -107,8 +107,10 @@ cc_test { static_libs: [ "VtsHalWifiV1_0TargetTestUtil", "android.hardware.wifi@1.0", + "android.hardware.wifi.hostapd@1.0", "libwifi-system-iface", ], + disable_framework: true, test_suites: [ "general-tests", "vts", diff --git a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp index 96b4501360..28b16168f5 100644 --- a/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp +++ b/wifi/1.0/vts/functional/wifi_ap_iface_hidl_test.cpp @@ -15,9 +15,9 @@ */ #include <android-base/logging.h> - #include <android/hardware/wifi/1.0/IWifi.h> #include <android/hardware/wifi/1.0/IWifiApIface.h> +#include <android/hardware/wifi/hostapd/1.0/IHostapd.h> #include <gtest/gtest.h> #include <hidl/GtestPrinter.h> #include <hidl/ServiceManagement.h> @@ -26,6 +26,7 @@ #include "wifi_hidl_test_utils.h" using ::android::sp; +using ::android::hardware::wifi::hostapd::V1_0::IHostapd; using ::android::hardware::wifi::V1_0::IfaceType; using ::android::hardware::wifi::V1_0::IWifi; using ::android::hardware::wifi::V1_0::IWifiApIface; @@ -38,6 +39,10 @@ using ::android::hardware::wifi::V1_0::WifiStatusCode; class WifiApIfaceHidlTest : public ::testing::TestWithParam<std::string> { public: virtual void SetUp() override { + if (android::hardware::getAllHalInstanceNames(IHostapd::descriptor) + .empty()) { + GTEST_SKIP() << "Device does not support AP"; + } // Make sure test starts with a clean state stopWifi(GetInstanceName()); diff --git a/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp index 2e6ad32d64..66e1a807f0 100644 --- a/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp +++ b/wifi/1.0/vts/functional/wifi_chip_hidl_ap_test.cpp @@ -15,9 +15,9 @@ */ #include <android-base/logging.h> - #include <android/hardware/wifi/1.0/IWifi.h> #include <android/hardware/wifi/1.0/IWifiChip.h> +#include <android/hardware/wifi/hostapd/1.0/IHostapd.h> #include <gtest/gtest.h> #include <hidl/GtestPrinter.h> #include <hidl/ServiceManagement.h> @@ -26,6 +26,7 @@ #include "wifi_hidl_test_utils.h" using ::android::sp; +using ::android::hardware::wifi::hostapd::V1_0::IHostapd; using ::android::hardware::wifi::V1_0::ChipModeId; using ::android::hardware::wifi::V1_0::IfaceType; using ::android::hardware::wifi::V1_0::IWifi; @@ -41,6 +42,10 @@ using ::android::hardware::wifi::V1_0::WifiStatusCode; class WifiChipHidlApTest : public ::testing::TestWithParam<std::string> { public: virtual void SetUp() override { + if (android::hardware::getAllHalInstanceNames(IHostapd::descriptor) + .empty()) { + GTEST_SKIP() << "Device does not support AP"; + } // Make sure test starts with a clean state stopWifi(GetInstanceName()); diff --git a/wifi/1.1/vts/functional/Android.bp b/wifi/1.1/vts/functional/Android.bp index 80486425c1..a8f3470c1a 100644 --- a/wifi/1.1/vts/functional/Android.bp +++ b/wifi/1.1/vts/functional/Android.bp @@ -39,6 +39,7 @@ cc_test { "android.hardware.wifi@1.5", "libwifi-system-iface", ], + disable_framework: true, test_suites: [ "general-tests", "vts", diff --git a/wifi/1.4/vts/functional/Android.bp b/wifi/1.4/vts/functional/Android.bp index 14ebbe3bb8..f86869bf61 100644 --- a/wifi/1.4/vts/functional/Android.bp +++ b/wifi/1.4/vts/functional/Android.bp @@ -14,7 +14,6 @@ // limitations under the License. // -// SoftAP-specific tests, similar to VtsHalWifiApV1_0TargetTest. package { // See: http://go/android-license-faq // A large-scale-change added 'default_applicable_licenses' to import @@ -25,11 +24,32 @@ package { } cc_test { + name: "VtsHalWifiV1_4TargetTest", + defaults: ["VtsHalTargetTestDefaults"], + srcs: [ + "wifi_chip_hidl_test.cpp", + ], + static_libs: [ + "VtsHalWifiV1_0TargetTestUtil", + "android.hardware.wifi@1.0", + "android.hardware.wifi@1.1", + "android.hardware.wifi@1.2", + "android.hardware.wifi@1.3", + "android.hardware.wifi@1.4", + "libwifi-system-iface", + ], + test_suites: [ + "general-tests", + "vts", + ], +} + +// SoftAP-specific tests, similar to VtsHalWifiApV1_0TargetTest. +cc_test { name: "VtsHalWifiApV1_4TargetTest", defaults: ["VtsHalTargetTestDefaults"], srcs: [ "wifi_ap_iface_hidl_test.cpp", - "wifi_chip_hidl_test.cpp", ], static_libs: [ "VtsHalWifiV1_0TargetTestUtil", @@ -38,8 +58,10 @@ cc_test { "android.hardware.wifi@1.2", "android.hardware.wifi@1.3", "android.hardware.wifi@1.4", + "android.hardware.wifi.hostapd@1.0", "libwifi-system-iface", ], + disable_framework: true, test_suites: [ "general-tests", "vts", diff --git a/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp index 5b0f1736ea..756afa5122 100644 --- a/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp +++ b/wifi/1.4/vts/functional/wifi_ap_iface_hidl_test.cpp @@ -16,6 +16,7 @@ #include <android/hardware/wifi/1.4/IWifi.h> #include <android/hardware/wifi/1.4/IWifiApIface.h> +#include <android/hardware/wifi/hostapd/1.0/IHostapd.h> #include <gtest/gtest.h> #include <hidl/GtestPrinter.h> #include <hidl/ServiceManagement.h> @@ -25,6 +26,7 @@ using ::android::sp; using ::android::hardware::hidl_array; +using ::android::hardware::wifi::hostapd::V1_0::IHostapd; using ::android::hardware::wifi::V1_0::WifiStatus; using ::android::hardware::wifi::V1_0::WifiStatusCode; using ::android::hardware::wifi::V1_4::IWifi; @@ -36,6 +38,10 @@ using ::android::hardware::wifi::V1_4::IWifiApIface; class WifiApIfaceHidlTest : public ::testing::TestWithParam<std::string> { public: virtual void SetUp() override { + if (android::hardware::getAllHalInstanceNames(IHostapd::descriptor) + .empty()) { + GTEST_SKIP() << "Device does not support AP"; + } // Make sure to start with a clean state stopWifi(GetInstanceName()); diff --git a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp index 8cb7e22f0e..114fe4f32c 100644 --- a/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp +++ b/wifi/supplicant/1.0/vts/functional/supplicant_hidl_test_utils.cpp @@ -317,7 +317,7 @@ bool turnOnExcessiveLogging(const sp<ISupplicant>& supplicant) { } bool waitForFrameworkReady() { - int waitCount = 10; + int waitCount = 15; do { // Check whether package service is ready or not. if (!testing::checkSubstringInCommandOutput( diff --git a/wifi/supplicant/1.4/vts/functional/Android.bp b/wifi/supplicant/1.4/vts/functional/Android.bp index 8cbe04f686..57ee83073b 100644 --- a/wifi/supplicant/1.4/vts/functional/Android.bp +++ b/wifi/supplicant/1.4/vts/functional/Android.bp @@ -77,7 +77,6 @@ cc_test { "general-tests", "vts", ], - disable_framework: true, } cc_test { @@ -108,5 +107,4 @@ cc_test { "general-tests", "vts", ], - disable_framework: true, } |