Merge "Camera2: Add distortion correction support" into pi-dev
diff --git a/audio/4.0/config/audio_policy_configuration.xsd b/audio/4.0/config/audio_policy_configuration.xsd
index e5b4449..34c2b11 100644
--- a/audio/4.0/config/audio_policy_configuration.xsd
+++ b/audio/4.0/config/audio_policy_configuration.xsd
@@ -104,7 +104,7 @@
<xs:element name="devicePorts" type="devicePorts" minOccurs="0"/>
<xs:element name="routes" type="routes" minOccurs="0"/>
</xs:sequence>
- <xs:attribute name="name" type="xsd:string" use="required"/>
+ <xs:attribute name="name" type="xs:string" use="required"/>
<xs:attribute name="halVersion" type="halVersion" use="required"/>
</xs:complexType>
<xs:unique name="mixPortNameUniqueness">
diff --git a/audio/common/4.0/types.hal b/audio/common/4.0/types.hal
index dfc350e..e55491d 100644
--- a/audio/common/4.0/types.hal
+++ b/audio/common/4.0/types.hal
@@ -373,21 +373,21 @@
OUT_TOP_BACK_LEFT = 0x8000,
OUT_TOP_BACK_CENTER = 0x10000,
OUT_TOP_BACK_RIGHT = 0x20000,
- OUT_TOP_CENTER_LEFT = 0x40000,
- OUT_TOP_CENTER_RIGHT = 0x80000,
+ OUT_TOP_SIDE_LEFT = 0x40000,
+ OUT_TOP_SIDE_RIGHT = 0x80000,
OUT_MONO = OUT_FRONT_LEFT,
OUT_STEREO = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT),
OUT_2POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT | OUT_LOW_FREQUENCY),
OUT_2POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
- OUT_TOP_CENTER_LEFT | OUT_TOP_CENTER_RIGHT),
+ OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
OUT_2POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
- OUT_TOP_CENTER_LEFT | OUT_TOP_CENTER_RIGHT |
+ OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT |
OUT_LOW_FREQUENCY),
OUT_3POINT0POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_CENTER | OUT_FRONT_RIGHT |
- OUT_TOP_CENTER_LEFT | OUT_TOP_CENTER_RIGHT),
+ OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
OUT_3POINT1POINT2 = (OUT_FRONT_LEFT | OUT_FRONT_CENTER | OUT_FRONT_RIGHT |
- OUT_TOP_CENTER_LEFT | OUT_TOP_CENTER_RIGHT |
+ OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT |
OUT_LOW_FREQUENCY),
OUT_QUAD = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
OUT_BACK_LEFT | OUT_BACK_RIGHT),
@@ -406,6 +406,10 @@
OUT_5POINT1_SIDE = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
+ OUT_5POINT1POINT2 = (OUT_5POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
+ OUT_5POINT1POINT4 = (OUT_5POINT1 |
+ OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT |
+ OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT),
OUT_6POINT1 = (OUT_FRONT_LEFT | OUT_FRONT_RIGHT |
OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
OUT_BACK_LEFT | OUT_BACK_RIGHT |
@@ -415,6 +419,10 @@
OUT_FRONT_CENTER | OUT_LOW_FREQUENCY |
OUT_BACK_LEFT | OUT_BACK_RIGHT |
OUT_SIDE_LEFT | OUT_SIDE_RIGHT),
+ OUT_7POINT1POINT2 = (OUT_7POINT1 | OUT_TOP_SIDE_LEFT | OUT_TOP_SIDE_RIGHT),
+ OUT_7POINT1POINT4 = (OUT_7POINT1 |
+ OUT_TOP_FRONT_LEFT | OUT_TOP_FRONT_RIGHT |
+ OUT_TOP_BACK_LEFT | OUT_TOP_BACK_RIGHT),
// Note that the 2.0 OUT_ALL* have been moved to helper functions
/* These are bits only, not complete values */
diff --git a/audio/common/all-versions/test/utility/include/utility/ReturnIn.h b/audio/common/all-versions/test/utility/include/utility/ReturnIn.h
index 2b92a21..7fd0d4a 100644
--- a/audio/common/all-versions/test/utility/include/utility/ReturnIn.h
+++ b/audio/common/all-versions/test/utility/include/utility/ReturnIn.h
@@ -45,7 +45,7 @@
template <class Head, class... Tail>
void set(Head&& head, Tail&&... tail) {
std::get<sizeof...(ResultStore) - sizeof...(Tail) - 1>(results) = std::forward<Head>(head);
- set(tail...);
+ set(std::forward<Tail>(tail)...);
}
// Trivial case
void set() {}
@@ -56,7 +56,7 @@
} // namespace detail
// Generate the HIDL synchronous callback with a copy policy
-// Input: the variables (lvalue reference) where to save the return values
+// Input: the variables (lvalue references) where to copy the return values
// Output: the callback to provide to a HIDL call with a synchronous callback
// The output parameters *will be copied* do not use this function if you have
// a zero copy policy
diff --git a/audio/common/all-versions/util/include/common/all-versions/VersionUtils.h b/audio/common/all-versions/util/include/common/all-versions/VersionUtils.h
index a998b06..70c3d56 100644
--- a/audio/common/all-versions/util/include/common/all-versions/VersionUtils.h
+++ b/audio/common/all-versions/util/include/common/all-versions/VersionUtils.h
@@ -52,6 +52,12 @@
return EnumConverter<Source, Destination>{source};
}
+/** Allows converting an enum to its bitfield or itself. */
+template <class Enum>
+EnumConverter<Enum> mkBitfield(Enum value) {
+ return EnumConverter<Enum>{value};
+}
+
} // namespace utils
} // namespace common
} // namespace audio
diff --git a/audio/core/4.0/vts/OWNERS b/audio/core/4.0/vts/OWNERS
new file mode 100644
index 0000000..8711a9f
--- /dev/null
+++ b/audio/core/4.0/vts/OWNERS
@@ -0,0 +1,5 @@
+elaurent@google.com
+krocard@google.com
+mnaganov@google.com
+yim@google.com
+zhuoyao@google.com
\ No newline at end of file
diff --git a/audio/core/4.0/vts/functional/Android.bp b/audio/core/4.0/vts/functional/Android.bp
new file mode 100644
index 0000000..dde3e7b
--- /dev/null
+++ b/audio/core/4.0/vts/functional/Android.bp
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2017 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.
+//
+
+cc_test {
+ name: "VtsHalAudioV4_0TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "AudioPrimaryHidlHalTest.cpp",
+ "ValidateAudioConfiguration.cpp"
+ ],
+ static_libs: [
+ "android.hardware.audio.common.test.utility",
+ "android.hardware.audio@4.0",
+ "android.hardware.audio.common@4.0",
+ "libxml2",
+ ],
+ shared_libs: [
+ "libicuuc",
+ ],
+ header_libs: [
+ "android.hardware.audio.common.util@all-versions",
+ ],
+}
diff --git a/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp b/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp
new file mode 100644
index 0000000..a568a3c
--- /dev/null
+++ b/audio/core/4.0/vts/functional/AudioPrimaryHidlHalTest.cpp
@@ -0,0 +1,1324 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsHalAudioV4_0TargetTest"
+
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+#include <cstdio>
+#include <initializer_list>
+#include <limits>
+#include <string>
+#include <vector>
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+
+#include <android-base/logging.h>
+
+#include <android/hardware/audio/4.0/IDevice.h>
+#include <android/hardware/audio/4.0/IDevicesFactory.h>
+#include <android/hardware/audio/4.0/IPrimaryDevice.h>
+#include <android/hardware/audio/4.0/types.h>
+#include <android/hardware/audio/common/4.0/types.h>
+
+#include <common/all-versions/VersionUtils.h>
+
+#include "utility/AssertOk.h"
+#include "utility/Documentation.h"
+#include "utility/EnvironmentTearDown.h"
+#define AUDIO_HAL_VERSION V4_0
+#include "utility/PrettyPrintAudioTypes.h"
+#include "utility/ReturnIn.h"
+
+using std::initializer_list;
+using std::string;
+using std::to_string;
+using std::vector;
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::hidl_bitfield;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::audio::V4_0::AudioDrain;
+using ::android::hardware::audio::V4_0::DeviceAddress;
+using ::android::hardware::audio::V4_0::IDevice;
+using ::android::hardware::audio::V4_0::IPrimaryDevice;
+using TtyMode = ::android::hardware::audio::V4_0::IPrimaryDevice::TtyMode;
+using ::android::hardware::audio::V4_0::IDevicesFactory;
+using ::android::hardware::audio::V4_0::IStream;
+using ::android::hardware::audio::V4_0::IStreamIn;
+using ::android::hardware::audio::V4_0::TimeSpec;
+using ReadParameters = ::android::hardware::audio::V4_0::IStreamIn::ReadParameters;
+using ReadStatus = ::android::hardware::audio::V4_0::IStreamIn::ReadStatus;
+using ::android::hardware::audio::V4_0::IStreamOut;
+using ::android::hardware::audio::V4_0::IStreamOutCallback;
+using ::android::hardware::audio::V4_0::MmapBufferInfo;
+using ::android::hardware::audio::V4_0::MmapPosition;
+using ::android::hardware::audio::V4_0::ParameterValue;
+using ::android::hardware::audio::V4_0::Result;
+using ::android::hardware::audio::V4_0::SourceMetadata;
+using ::android::hardware::audio::V4_0::SinkMetadata;
+using ::android::hardware::audio::common::V4_0::AudioChannelMask;
+using ::android::hardware::audio::common::V4_0::AudioConfig;
+using ::android::hardware::audio::common::V4_0::AudioDevice;
+using ::android::hardware::audio::common::V4_0::AudioFormat;
+using ::android::hardware::audio::common::V4_0::AudioHandleConsts;
+using ::android::hardware::audio::common::V4_0::AudioHwSync;
+using ::android::hardware::audio::common::V4_0::AudioInputFlag;
+using ::android::hardware::audio::common::V4_0::AudioIoHandle;
+using ::android::hardware::audio::common::V4_0::AudioMode;
+using ::android::hardware::audio::common::V4_0::AudioOffloadInfo;
+using ::android::hardware::audio::common::V4_0::AudioOutputFlag;
+using ::android::hardware::audio::common::V4_0::AudioSource;
+using ::android::hardware::audio::common::V4_0::ThreadInfo;
+using ::android::hardware::audio::common::utils::mkBitfield;
+
+using namespace ::android::hardware::audio::common::test::utility;
+
+class AudioHidlTestEnvironment : public ::Environment {
+ public:
+ virtual void registerTestServices() override { registerTestService<IDevicesFactory>(); }
+};
+
+// Instance to register global tearDown
+static AudioHidlTestEnvironment* environment;
+
+class HidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ protected:
+ // Convenient member to store results
+ Result res;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+////////////////////// getService audio_devices_factory //////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+// Test all audio devices
+class AudioHidlTest : public HidlTest {
+ public:
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(HidlTest::SetUp()); // setup base
+
+ if (devicesFactory == nullptr) {
+ environment->registerTearDown([] { devicesFactory.clear(); });
+ devicesFactory = ::testing::VtsHalHidlTargetTestBase::getService<IDevicesFactory>(
+ environment->getServiceName<IDevicesFactory>("default"));
+ }
+ ASSERT_TRUE(devicesFactory != nullptr);
+ }
+
+ protected:
+ // Cache the devicesFactory retrieval to speed up each test by ~0.5s
+ static sp<IDevicesFactory> devicesFactory;
+};
+sp<IDevicesFactory> AudioHidlTest::devicesFactory;
+
+TEST_F(AudioHidlTest, GetAudioDevicesFactoryService) {
+ doc::test("test the getService (called in SetUp)");
+}
+
+TEST_F(AudioHidlTest, OpenDeviceInvalidParameter) {
+ doc::test("test passing an invalid parameter to openDevice");
+ Result result;
+ sp<IDevice> device;
+ ASSERT_OK(devicesFactory->openDevice("Non existing device", returnIn(result, device)));
+ ASSERT_EQ(Result::INVALID_ARGUMENTS, result);
+ ASSERT_TRUE(device == nullptr);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// openDevice primary ///////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+// Test the primary device
+class AudioPrimaryHidlTest : public AudioHidlTest {
+ public:
+ /** Primary HAL test are NOT thread safe. */
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp()); // setup base
+
+ if (device == nullptr) {
+ Result result;
+ sp<IDevice> baseDevice;
+ ASSERT_OK(devicesFactory->openDevice("primary", returnIn(result, baseDevice)));
+ ASSERT_OK(result);
+ ASSERT_TRUE(baseDevice != nullptr);
+
+ environment->registerTearDown([] { device.clear(); });
+ device = IPrimaryDevice::castFrom(baseDevice);
+ ASSERT_TRUE(device != nullptr);
+ }
+ }
+
+ protected:
+ // Cache the device opening to speed up each test by ~0.5s
+ static sp<IPrimaryDevice> device;
+};
+sp<IPrimaryDevice> AudioPrimaryHidlTest::device;
+
+TEST_F(AudioPrimaryHidlTest, OpenPrimaryDevice) {
+ doc::test("Test the openDevice (called in SetUp)");
+}
+
+TEST_F(AudioPrimaryHidlTest, Init) {
+ doc::test("Test that the audio primary hal initialized correctly");
+ ASSERT_OK(device->initCheck());
+}
+
+//////////////////////////////////////////////////////////////////////////////
+///////////////////// {set,get}{Master,Mic}{Mute,Volume} /////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+template <class Property>
+class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest {
+ protected:
+ /** Test a property getter and setter. */
+ template <class Getter, class Setter>
+ void testAccessors(const string& propertyName, const vector<Property>& valuesToTest,
+ Setter setter, Getter getter, const vector<Property>& invalidValues = {}) {
+ Property initialValue; // Save initial value to restore it at the end
+ // of the test
+ ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue)));
+ ASSERT_OK(res);
+
+ for (Property setValue : valuesToTest) {
+ SCOPED_TRACE("Test " + propertyName + " getter and setter for " +
+ testing::PrintToString(setValue));
+ ASSERT_OK((device.get()->*setter)(setValue));
+ Property getValue;
+ // Make sure the getter returns the same value just set
+ ASSERT_OK((device.get()->*getter)(returnIn(res, getValue)));
+ ASSERT_OK(res);
+ EXPECT_EQ(setValue, getValue);
+ }
+
+ for (Property invalidValue : invalidValues) {
+ SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " +
+ testing::PrintToString(invalidValue));
+ EXPECT_RESULT(Result::INVALID_ARGUMENTS, (device.get()->*setter)(invalidValue));
+ }
+
+ ASSERT_OK((device.get()->*setter)(initialValue)); // restore initial value
+ }
+
+ /** Test the getter and setter of an optional feature. */
+ template <class Getter, class Setter>
+ void testOptionalAccessors(const string& propertyName, const vector<Property>& valuesToTest,
+ Setter setter, Getter getter,
+ const vector<Property>& invalidValues = {}) {
+ doc::test("Test the optional " + propertyName + " getters and setter");
+ {
+ SCOPED_TRACE("Test feature support by calling the getter");
+ Property initialValue;
+ ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue)));
+ if (res == Result::NOT_SUPPORTED) {
+ doc::partialTest(propertyName + " getter is not supported");
+ return;
+ }
+ ASSERT_OK(res); // If it is supported it must succeed
+ }
+ // The feature is supported, test it
+ testAccessors(propertyName, valuesToTest, setter, getter, invalidValues);
+ }
+};
+
+using BoolAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<bool>;
+
+TEST_F(BoolAccessorPrimaryHidlTest, MicMuteTest) {
+ doc::test("Check that the mic can be muted and unmuted");
+ testAccessors("mic mute", {true, false, true}, &IDevice::setMicMute, &IDevice::getMicMute);
+ // TODO: check that the mic is really muted (all sample are 0)
+}
+
+TEST_F(BoolAccessorPrimaryHidlTest, MasterMuteTest) {
+ doc::test(
+ "If master mute is supported, try to mute and unmute the master "
+ "output");
+ testOptionalAccessors("master mute", {true, false, true}, &IDevice::setMasterMute,
+ &IDevice::getMasterMute);
+ // TODO: check that the master volume is really muted
+}
+
+using FloatAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<float>;
+TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) {
+ doc::test("Test the master volume if supported");
+ testOptionalAccessors(
+ "master volume", {0, 0.5, 1}, &IDevice::setMasterVolume, &IDevice::getMasterVolume,
+ {-0.1, 1.1, NAN, INFINITY, -INFINITY, 1 + std::numeric_limits<float>::epsilon()});
+ // TODO: check that the master volume is really changed
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////// AudioPatches ////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+class AudioPatchPrimaryHidlTest : public AudioPrimaryHidlTest {
+ protected:
+ bool areAudioPatchesSupported() {
+ auto result = device->supportsAudioPatches();
+ EXPECT_IS_OK(result);
+ return result;
+ }
+};
+
+TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) {
+ doc::test("Test if audio patches are supported");
+ if (!areAudioPatchesSupported()) {
+ doc::partialTest("Audio patches are not supported");
+ return;
+ }
+ // TODO: test audio patches
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////// Required and recommended audio format support ///////////////
+// From:
+// https://source.android.com/compatibility/android-cdd.html#5_4_audio_recording
+// From:
+// https://source.android.com/compatibility/android-cdd.html#5_5_audio_playback
+/////////// TODO: move to the beginning of the file for easier update ////////
+//////////////////////////////////////////////////////////////////////////////
+
+class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest {
+ public:
+ // Cache result ?
+ static const vector<AudioConfig> getRequiredSupportPlaybackAudioConfig() {
+ return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO},
+ {8000, 11025, 16000, 22050, 32000, 44100},
+ {AudioFormat::PCM_16_BIT});
+ }
+
+ static const vector<AudioConfig> getRecommendedSupportPlaybackAudioConfig() {
+ return combineAudioConfig({AudioChannelMask::OUT_STEREO, AudioChannelMask::OUT_MONO},
+ {24000, 48000}, {AudioFormat::PCM_16_BIT});
+ }
+
+ static const vector<AudioConfig> getSupportedPlaybackAudioConfig() {
+ // TODO: retrieve audio config supported by the platform
+ // as declared in the policy configuration
+ return {};
+ }
+
+ static const vector<AudioConfig> getRequiredSupportCaptureAudioConfig() {
+ return combineAudioConfig({AudioChannelMask::IN_MONO}, {8000, 11025, 16000, 44100},
+ {AudioFormat::PCM_16_BIT});
+ }
+ static const vector<AudioConfig> getRecommendedSupportCaptureAudioConfig() {
+ return combineAudioConfig({AudioChannelMask::IN_STEREO}, {22050, 48000},
+ {AudioFormat::PCM_16_BIT});
+ }
+ static const vector<AudioConfig> getSupportedCaptureAudioConfig() {
+ // TODO: retrieve audio config supported by the platform
+ // as declared in the policy configuration
+ return {};
+ }
+
+ private:
+ static const vector<AudioConfig> combineAudioConfig(vector<AudioChannelMask> channelMasks,
+ vector<uint32_t> sampleRates,
+ vector<AudioFormat> formats) {
+ vector<AudioConfig> configs;
+ for (auto channelMask : channelMasks) {
+ for (auto sampleRate : sampleRates) {
+ for (auto format : formats) {
+ AudioConfig config{};
+ // leave offloadInfo to 0
+ config.channelMask = mkBitfield(channelMask);
+ config.sampleRateHz = sampleRate;
+ config.format = format;
+ // FIXME: leave frameCount to 0 ?
+ configs.push_back(config);
+ }
+ }
+ }
+ return configs;
+ }
+};
+
+/** Generate a test name based on an audio config.
+ *
+ * As the only parameter changing are channel mask and sample rate,
+ * only print those ones in the test name.
+ */
+static string generateTestName(const testing::TestParamInfo<AudioConfig>& info) {
+ const AudioConfig& config = info.param;
+ return to_string(info.index) + "__" + to_string(config.sampleRateHz) + "_" +
+ // "MONO" is more clear than "FRONT_LEFT"
+ ((config.channelMask == mkBitfield(AudioChannelMask::OUT_MONO) ||
+ config.channelMask == mkBitfield(AudioChannelMask::IN_MONO))
+ ? "MONO"
+ : ::testing::PrintToString(config.channelMask));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+///////////////////////////// getInputBufferSize /////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+// FIXME: execute input test only if platform declares
+// android.hardware.microphone
+// how to get this value ? is it a property ???
+
+class AudioCaptureConfigPrimaryTest : public AudioConfigPrimaryTest,
+ public ::testing::WithParamInterface<AudioConfig> {
+ protected:
+ void inputBufferSizeTest(const AudioConfig& audioConfig, bool supportRequired) {
+ uint64_t bufferSize;
+ ASSERT_OK(device->getInputBufferSize(audioConfig, returnIn(res, bufferSize)));
+
+ switch (res) {
+ case Result::INVALID_ARGUMENTS:
+ EXPECT_FALSE(supportRequired);
+ break;
+ case Result::OK:
+ // Check that the buffer is of a sane size
+ // For now only that it is > 0
+ EXPECT_GT(bufferSize, uint64_t(0));
+ break;
+ default:
+ FAIL() << "Invalid return status: " << ::testing::PrintToString(res);
+ }
+ }
+};
+
+// Test that the required capture config and those declared in the policy are
+// indeed supported
+class RequiredInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {};
+TEST_P(RequiredInputBufferSizeTest, RequiredInputBufferSizeTest) {
+ doc::test(
+ "Input buffer size must be retrievable for a format with required "
+ "support.");
+ inputBufferSizeTest(GetParam(), true);
+}
+INSTANTIATE_TEST_CASE_P(
+ RequiredInputBufferSize, RequiredInputBufferSizeTest,
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
+ &generateTestName);
+INSTANTIATE_TEST_CASE_P(
+ SupportedInputBufferSize, RequiredInputBufferSizeTest,
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
+ &generateTestName);
+
+// Test that the recommended capture config are supported or lead to a
+// INVALID_ARGUMENTS return
+class OptionalInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {};
+TEST_P(OptionalInputBufferSizeTest, OptionalInputBufferSizeTest) {
+ doc::test(
+ "Input buffer size should be retrievable for a format with recommended "
+ "support.");
+ inputBufferSizeTest(GetParam(), false);
+}
+INSTANTIATE_TEST_CASE_P(
+ RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest,
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
+ &generateTestName);
+
+//////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// setScreenState ///////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_F(AudioPrimaryHidlTest, setScreenState) {
+ doc::test("Check that the hal can receive the screen state");
+ for (bool turnedOn : {false, true, true, false, false}) {
+ auto ret = device->setScreenState(turnedOn);
+ ASSERT_IS_OK(ret);
+ Result result = ret;
+ auto okOrNotSupported = {Result::OK, Result::NOT_SUPPORTED};
+ ASSERT_RESULT(okOrNotSupported, result);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////// {get,set}Parameters /////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_F(AudioPrimaryHidlTest, getParameters) {
+ doc::test("Check that the hal can set and get parameters");
+ hidl_vec<ParameterValue> context;
+ hidl_vec<hidl_string> keys;
+ hidl_vec<ParameterValue> values;
+ ASSERT_OK(device->getParameters(context, keys, returnIn(res, values)));
+ ASSERT_OK(device->setParameters(context, values));
+ values.resize(0);
+ ASSERT_OK(device->setParameters(context, values));
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////// debugDebug //////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+template <class DebugDump>
+static void testDebugDump(DebugDump debugDump) {
+ // File descriptors to our pipe. fds[0] corresponds to the read end and
+ // fds[1] to the write end.
+ int fds[2];
+ ASSERT_EQ(0, pipe2(fds, O_NONBLOCK)) << errno;
+
+ // Make sure that the pipe is at least 1 MB in size. The test process runs
+ // in su domain, so it should be safe to make this call.
+ fcntl(fds[0], F_SETPIPE_SZ, 1 << 20);
+
+ // Wrap the temporary file file descriptor in a native handle
+ auto* nativeHandle = native_handle_create(1, 0);
+ ASSERT_NE(nullptr, nativeHandle);
+ nativeHandle->data[0] = fds[1];
+
+ // Wrap this native handle in a hidl handle
+ hidl_handle handle;
+ handle.setTo(nativeHandle, false /*take ownership*/);
+
+ ASSERT_OK(debugDump(handle));
+
+ // Check that at least one bit was written by the hal
+ // TODO: debugDump does not return a Result.
+ // This mean that the hal can not report that it not implementing the
+ // function.
+ char buff;
+ if (read(fds[0], &buff, 1) != 1) {
+ doc::note("debugDump does not seem implemented");
+ }
+ EXPECT_EQ(0, close(fds[0])) << errno;
+ EXPECT_EQ(0, close(fds[1])) << errno;
+}
+
+TEST_F(AudioPrimaryHidlTest, DebugDump) {
+ doc::test("Check that the hal can dump its state without error");
+ testDebugDump([](const auto& handle) { return device->debug(handle, {/* options */}); });
+}
+
+TEST_F(AudioPrimaryHidlTest, DebugDumpInvalidArguments) {
+ doc::test("Check that the hal dump doesn't crash on invalid arguments");
+ ASSERT_OK(device->debug(hidl_handle(), {/* options */}));
+}
+
+TEST_F(AudioPrimaryHidlTest, SetConnectedState) {
+ doc::test("Check that the HAL can be notified of device connection and deconnection");
+ using AD = AudioDevice;
+ for (auto deviceType : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) {
+ SCOPED_TRACE("device=" + ::testing::PrintToString(deviceType));
+ for (bool state : {true, false}) {
+ SCOPED_TRACE("state=" + ::testing::PrintToString(state));
+ DeviceAddress address = {};
+ address.device = deviceType;
+ auto ret = device->setConnectedState(address, state);
+ ASSERT_TRUE(ret.isOk());
+ if (res == Result::NOT_SUPPORTED) {
+ doc::partialTest("setConnectedState is not supported");
+ return;
+ }
+ ASSERT_OK(res);
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+////////////////////////// open{Output,Input}Stream //////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+template <class Stream>
+class OpenStreamTest : public AudioConfigPrimaryTest,
+ public ::testing::WithParamInterface<AudioConfig> {
+ protected:
+ template <class Open>
+ void testOpen(Open openStream, const AudioConfig& config) {
+ // FIXME: Open a stream without an IOHandle
+ // This is not required to be accepted by hal implementations
+ AudioIoHandle ioHandle = (AudioIoHandle)AudioHandleConsts::AUDIO_IO_HANDLE_NONE;
+ AudioConfig suggestedConfig{};
+ ASSERT_OK(openStream(ioHandle, config, returnIn(res, stream, suggestedConfig)));
+
+ // TODO: only allow failure for RecommendedPlaybackAudioConfig
+ switch (res) {
+ case Result::OK:
+ ASSERT_TRUE(stream != nullptr);
+ audioConfig = config;
+ break;
+ case Result::INVALID_ARGUMENTS:
+ ASSERT_TRUE(stream == nullptr);
+ AudioConfig suggestedConfigRetry;
+ // Could not open stream with config, try again with the
+ // suggested one
+ ASSERT_OK(openStream(ioHandle, suggestedConfig,
+ returnIn(res, stream, suggestedConfigRetry)));
+ // This time it must succeed
+ ASSERT_OK(res);
+ ASSERT_TRUE(stream != nullptr);
+ audioConfig = suggestedConfig;
+ break;
+ default:
+ FAIL() << "Invalid return status: " << ::testing::PrintToString(res);
+ }
+ open = true;
+ }
+
+ Return<Result> closeStream() {
+ open = false;
+ return stream->close();
+ }
+
+ private:
+ void TearDown() override {
+ if (open) {
+ ASSERT_OK(stream->close());
+ }
+ }
+
+ protected:
+ AudioConfig audioConfig;
+ DeviceAddress address = {};
+ sp<Stream> stream;
+ bool open = false;
+};
+
+////////////////////////////// openOutputStream //////////////////////////////
+
+class OutputStreamTest : public OpenStreamTest<IStreamOut> {
+ virtual void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base
+ address.device = AudioDevice::OUT_DEFAULT;
+ const AudioConfig& config = GetParam();
+ // TODO: test all flag combination
+ auto flags = hidl_bitfield<AudioOutputFlag>(AudioOutputFlag::NONE);
+ SourceMetadata metadata = {{{}}}; // create on track metadata
+ testOpen(
+ [&](AudioIoHandle handle, AudioConfig config, auto cb) {
+ return device->openOutputStream(handle, address, config, flags, metadata, cb);
+ },
+ config);
+ }
+};
+TEST_P(OutputStreamTest, OpenOutputStreamTest) {
+ doc::test(
+ "Check that output streams can be open with the required and "
+ "recommended config");
+ // Open done in SetUp
+}
+INSTANTIATE_TEST_CASE_P(
+ RequiredOutputStreamConfigSupport, OutputStreamTest,
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportPlaybackAudioConfig()),
+ &generateTestName);
+INSTANTIATE_TEST_CASE_P(
+ SupportedOutputStreamConfig, OutputStreamTest,
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedPlaybackAudioConfig()),
+ &generateTestName);
+
+INSTANTIATE_TEST_CASE_P(
+ RecommendedOutputStreamConfigSupport, OutputStreamTest,
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportPlaybackAudioConfig()),
+ &generateTestName);
+
+////////////////////////////// openInputStream //////////////////////////////
+
+class InputStreamTest : public OpenStreamTest<IStreamIn> {
+ virtual void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base
+ address.device = AudioDevice::IN_DEFAULT;
+ const AudioConfig& config = GetParam();
+ // TODO: test all supported flags and source
+ auto flags = hidl_bitfield<AudioInputFlag>(AudioInputFlag::NONE);
+ SinkMetadata metadata = {{{AudioSource::DEFAULT, 1}}};
+ testOpen(
+ [&](AudioIoHandle handle, AudioConfig config, auto cb) {
+ return device->openInputStream(handle, address, config, flags, metadata, cb);
+ },
+ config);
+ }
+};
+
+TEST_P(InputStreamTest, OpenInputStreamTest) {
+ doc::test(
+ "Check that input streams can be open with the required and "
+ "recommended config");
+ // Open done in setup
+}
+INSTANTIATE_TEST_CASE_P(
+ RequiredInputStreamConfigSupport, InputStreamTest,
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
+ &generateTestName);
+INSTANTIATE_TEST_CASE_P(
+ SupportedInputStreamConfig, InputStreamTest,
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
+ &generateTestName);
+
+INSTANTIATE_TEST_CASE_P(
+ RecommendedInputStreamConfigSupport, InputStreamTest,
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
+ &generateTestName);
+
+//////////////////////////////////////////////////////////////////////////////
+////////////////////////////// IStream getters ///////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+/** Unpack the provided result.
+ * If the result is not OK, register a failure and return an undefined value. */
+template <class R>
+static R extract(Return<R> ret) {
+ if (!ret.isOk()) {
+ EXPECT_IS_OK(ret);
+ return R{};
+ }
+ return ret;
+}
+
+/* Could not find a way to write a test for two parametrized class fixure
+ * thus use this macro do duplicate tests for Input and Output stream */
+#define TEST_IO_STREAM(test_name, documentation, code) \
+ TEST_P(InputStreamTest, test_name) { \
+ doc::test(documentation); \
+ code; \
+ } \
+ TEST_P(OutputStreamTest, test_name) { \
+ doc::test(documentation); \
+ code; \
+ }
+
+TEST_IO_STREAM(GetFrameCount, "Check that the stream frame count == the one it was opened with",
+ ASSERT_EQ(audioConfig.frameCount, extract(stream->getFrameCount())))
+
+TEST_IO_STREAM(GetSampleRate, "Check that the stream sample rate == the one it was opened with",
+ ASSERT_EQ(audioConfig.sampleRateHz, extract(stream->getSampleRate())))
+
+TEST_IO_STREAM(GetChannelMask, "Check that the stream channel mask == the one it was opened with",
+ ASSERT_EQ(audioConfig.channelMask, extract(stream->getChannelMask())))
+
+TEST_IO_STREAM(GetFormat, "Check that the stream format == the one it was opened with",
+ ASSERT_EQ(audioConfig.format, extract(stream->getFormat())))
+
+// TODO: for now only check that the framesize is not incoherent
+TEST_IO_STREAM(GetFrameSize, "Check that the stream frame size == the one it was opened with",
+ ASSERT_GT(extract(stream->getFrameSize()), 0U))
+
+TEST_IO_STREAM(GetBufferSize, "Check that the stream buffer size== the one it was opened with",
+ ASSERT_GE(extract(stream->getBufferSize()), extract(stream->getFrameSize())));
+
+template <class Property, class CapablityGetter>
+static void testCapabilityGetter(const string& name, IStream* stream,
+ CapablityGetter capablityGetter,
+ Return<Property> (IStream::*getter)(),
+ Return<Result> (IStream::*setter)(Property),
+ bool currentMustBeSupported = true) {
+ hidl_vec<Property> capabilities;
+ auto ret = capablityGetter(stream, capabilities);
+ if (ret == Result::NOT_SUPPORTED) {
+ doc::partialTest(name + " is not supported");
+ return;
+ };
+ ASSERT_OK(ret);
+
+ if (currentMustBeSupported) {
+ Property currentValue = extract((stream->*getter)());
+ EXPECT_NE(std::find(capabilities.begin(), capabilities.end(), currentValue),
+ capabilities.end())
+ << "current " << name << " is not in the list of the supported ones "
+ << toString(capabilities);
+ }
+
+ // Check that all declared supported values are indeed supported
+ for (auto capability : capabilities) {
+ auto ret = (stream->*setter)(capability);
+ ASSERT_TRUE(ret.isOk());
+ if (ret == Result::NOT_SUPPORTED) {
+ doc::partialTest("Setter is not supported");
+ return;
+ }
+ ASSERT_OK(ret);
+ ASSERT_EQ(capability, extract((stream->*getter)()));
+ }
+}
+
+Result getSupportedSampleRates(IStream* stream, hidl_vec<uint32_t>& rates) {
+ Result res;
+ EXPECT_OK(stream->getSupportedSampleRates(extract(stream->getFormat()), returnIn(res, rates)));
+ return res;
+}
+
+Result getSupportedChannelMasks(IStream* stream,
+ hidl_vec<hidl_bitfield<AudioChannelMask>>& channels) {
+ Result res;
+ EXPECT_OK(
+ stream->getSupportedSampleRates(extract(stream->getFormat()), returnIn(res, channels)));
+ return res;
+}
+
+Result getSupportedFormats(IStream* stream, hidl_vec<AudioFormat>& capabilities) {
+ EXPECT_OK(stream->getSupportedFormats(returnIn(capabilities)));
+ // TODO: this should be an optional function
+ return Result::OK;
+}
+
+TEST_IO_STREAM(SupportedSampleRate, "Check that the stream sample rate is declared as supported",
+ testCapabilityGetter("getSupportedSampleRate", stream.get(),
+ &getSupportedSampleRates, &IStream::getSampleRate,
+ &IStream::setSampleRate,
+ // getSupportedSampleRate returns the native sampling rates,
+ // (the sampling rates that can be played without resampling)
+ // but other sampling rates can be supported by the HAL.
+ false))
+
+TEST_IO_STREAM(SupportedChannelMask, "Check that the stream channel mask is declared as supported",
+ testCapabilityGetter("getSupportedChannelMask", stream.get(),
+ &getSupportedChannelMasks, &IStream::getChannelMask,
+ &IStream::setChannelMask))
+
+TEST_IO_STREAM(SupportedFormat, "Check that the stream format is declared as supported",
+ testCapabilityGetter("getSupportedFormat", stream.get(), &getSupportedFormats,
+ &IStream::getFormat, &IStream::setFormat))
+
+static void testGetDevice(IStream* stream, AudioDevice expectedDevice) {
+ hidl_vec<DeviceAddress> devices;
+ Result res;
+ ASSERT_OK(stream->getDevices(returnIn(res, devices)));
+ if (res == Result::NOT_SUPPORTED) {
+ return doc::partialTest("GetDevices is not supported");
+ }
+ // The stream was constructed with one device, thus getDevices must only return one
+ ASSERT_EQ(1U, devices.size());
+ AudioDevice device = devices[0].device;
+ ASSERT_TRUE(device == expectedDevice)
+ << "Expected: " << ::testing::PrintToString(expectedDevice)
+ << "\n Actual: " << ::testing::PrintToString(device);
+}
+
+TEST_IO_STREAM(GetDevice, "Check that the stream device == the one it was opened with",
+ areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported")
+ : testGetDevice(stream.get(), address.device))
+
+static void testSetDevice(IStream* stream, const DeviceAddress& address) {
+ DeviceAddress otherAddress = address;
+ otherAddress.device = (address.device & AudioDevice::BIT_IN) == 0 ? AudioDevice::OUT_SPEAKER
+ : AudioDevice::IN_BUILTIN_MIC;
+ EXPECT_OK(stream->setDevices({otherAddress}));
+
+ ASSERT_OK(stream->setDevices({address})); // Go back to the original value
+}
+
+TEST_IO_STREAM(SetDevice, "Check that the stream can be rerouted to SPEAKER or BUILTIN_MIC",
+ areAudioPatchesSupported() ? doc::partialTest("Audio patches are supported")
+ : testSetDevice(stream.get(), address))
+
+static void testGetAudioProperties(IStream* stream, AudioConfig expectedConfig) {
+ uint32_t sampleRateHz;
+ hidl_bitfield<AudioChannelMask> mask;
+ AudioFormat format;
+
+ stream->getAudioProperties(returnIn(sampleRateHz, mask, format));
+
+ // FIXME: the qcom hal it does not currently negotiate the sampleRate &
+ // channel mask
+ EXPECT_EQ(expectedConfig.sampleRateHz, sampleRateHz);
+ EXPECT_EQ(expectedConfig.channelMask, mask);
+ EXPECT_EQ(expectedConfig.format, format);
+}
+
+TEST_IO_STREAM(GetAudioProperties,
+ "Check that the stream audio properties == the ones it was opened with",
+ testGetAudioProperties(stream.get(), audioConfig))
+
+static auto invalidArgsOrNotSupportedOrOK = {Result::INVALID_ARGUMENTS, Result::NOT_SUPPORTED,
+ Result::OK};
+TEST_IO_STREAM(SetHwAvSync, "Try to set hardware sync to an invalid value",
+ ASSERT_RESULT(invalidArgsOrNotSupportedOrOK, stream->setHwAvSync(666)))
+
+static void checkGetHwAVSync(IDevice* device) {
+ Result res;
+ AudioHwSync sync;
+ ASSERT_OK(device->getHwAvSync(returnIn(res, sync)));
+ if (res == Result::NOT_SUPPORTED) {
+ return doc::partialTest("getHwAvSync is not supported");
+ }
+ ASSERT_OK(res);
+}
+TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", checkGetHwAVSync(device.get()));
+
+static void checkGetNoParameter(IStream* stream, hidl_vec<hidl_string> keys,
+ initializer_list<Result> expectedResults) {
+ hidl_vec<ParameterValue> context;
+ hidl_vec<ParameterValue> parameters;
+ Result res;
+ ASSERT_OK(stream->getParameters(context, keys, returnIn(res, parameters)));
+ ASSERT_RESULT(expectedResults, res);
+ if (res == Result::OK) {
+ for (auto& parameter : parameters) {
+ ASSERT_EQ(0U, parameter.value.size()) << toString(parameter);
+ }
+ }
+}
+
+/* Get/Set parameter is intended to be an opaque channel between vendors app and
+ * their HALs.
+ * Thus can not be meaningfully tested.
+ */
+TEST_IO_STREAM(getEmptySetParameter, "Retrieve the values of an empty set",
+ checkGetNoParameter(stream.get(), {} /* keys */, {Result::OK}))
+
+TEST_IO_STREAM(getNonExistingParameter, "Retrieve the values of an non existing parameter",
+ checkGetNoParameter(stream.get(), {"Non existing key"} /* keys */,
+ {Result::NOT_SUPPORTED}))
+
+TEST_IO_STREAM(setEmptySetParameter, "Set the values of an empty set of parameters",
+ ASSERT_RESULT(Result::OK, stream->setParameters({}, {})))
+
+TEST_IO_STREAM(setNonExistingParameter, "Set the values of an non existing parameter",
+ // Unfortunately, the set_parameter legacy interface did not return any
+ // error code when a key is not supported.
+ // To allow implementation to just wrapped the legacy one, consider OK as a
+ // valid result for setting a non existing parameter.
+ ASSERT_RESULT(invalidArgsOrNotSupportedOrOK,
+ stream->setParameters({}, {{"non existing key", "0"}})))
+
+TEST_IO_STREAM(DebugDump, "Check that a stream can dump its state without error",
+ testDebugDump([this](const auto& handle) { return stream->debug(handle, {}); }))
+
+TEST_IO_STREAM(DebugDumpInvalidArguments,
+ "Check that the stream dump doesn't crash on invalid arguments",
+ ASSERT_OK(stream->debug(hidl_handle(), {})))
+
+//////////////////////////////////////////////////////////////////////////////
+////////////////////////////// addRemoveEffect ///////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_IO_STREAM(AddNonExistingEffect, "Adding a non existing effect should fail",
+ ASSERT_RESULT(Result::INVALID_ARGUMENTS, stream->addEffect(666)))
+TEST_IO_STREAM(RemoveNonExistingEffect, "Removing a non existing effect should fail",
+ ASSERT_RESULT(Result::INVALID_ARGUMENTS, stream->removeEffect(666)))
+
+// TODO: positive tests
+
+//////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// Control ////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_IO_STREAM(standby, "Make sure the stream can be put in stanby",
+ ASSERT_OK(stream->standby())) // can not fail
+
+static constexpr auto invalidStateOrNotSupported = {Result::INVALID_STATE, Result::NOT_SUPPORTED};
+
+TEST_IO_STREAM(startNoMmap, "Starting a mmaped stream before mapping it should fail",
+ ASSERT_RESULT(invalidStateOrNotSupported, stream->start()))
+
+TEST_IO_STREAM(stopNoMmap, "Stopping a mmaped stream before mapping it should fail",
+ ASSERT_RESULT(invalidStateOrNotSupported, stream->stop()))
+
+TEST_IO_STREAM(getMmapPositionNoMmap, "Get a stream Mmap position before mapping it should fail",
+ ASSERT_RESULT(invalidStateOrNotSupported, stream->stop()))
+
+TEST_IO_STREAM(close, "Make sure a stream can be closed", ASSERT_OK(closeStream()))
+TEST_IO_STREAM(closeTwice, "Make sure a stream can not be closed twice", ASSERT_OK(closeStream());
+ ASSERT_RESULT(Result::INVALID_STATE, closeStream()))
+
+static auto invalidArgsOrNotSupported = {Result::INVALID_ARGUMENTS, Result::NOT_SUPPORTED};
+static void testCreateTooBigMmapBuffer(IStream* stream) {
+ MmapBufferInfo info;
+ Result res;
+ // Assume that int max is a value too big to be allocated
+ // This is true currently with a 32bit media server, but might not when it
+ // will run in 64 bit
+ auto minSizeFrames = std::numeric_limits<int32_t>::max();
+ ASSERT_OK(stream->createMmapBuffer(minSizeFrames, returnIn(res, info)));
+ ASSERT_RESULT(invalidArgsOrNotSupported, res);
+}
+
+TEST_IO_STREAM(CreateTooBigMmapBuffer, "Create mmap buffer too big should fail",
+ testCreateTooBigMmapBuffer(stream.get()))
+
+static void testGetMmapPositionOfNonMmapedStream(IStream* stream) {
+ Result res;
+ MmapPosition position;
+ ASSERT_OK(stream->getMmapPosition(returnIn(res, position)));
+ ASSERT_RESULT(invalidArgsOrNotSupported, res);
+}
+
+TEST_IO_STREAM(GetMmapPositionOfNonMmapedStream,
+ "Retrieving the mmap position of a non mmaped stream should fail",
+ testGetMmapPositionOfNonMmapedStream(stream.get()))
+
+//////////////////////////////////////////////////////////////////////////////
+///////////////////////////////// StreamIn ///////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_P(InputStreamTest, GetAudioSource) {
+ doc::test("Retrieving the audio source of an input stream should always succeed");
+ AudioSource source;
+ ASSERT_OK(stream->getAudioSource(returnIn(res, source)));
+ if (res == Result::NOT_SUPPORTED) {
+ doc::partialTest("getAudioSource is not supported");
+ return;
+ }
+ ASSERT_OK(res);
+ ASSERT_EQ(AudioSource::DEFAULT, source);
+}
+
+static void testUnitaryGain(std::function<Return<Result>(float)> setGain) {
+ for (float value : (float[]){-INFINITY, -1.0, 1.0 + std::numeric_limits<float>::epsilon(), 2.0,
+ INFINITY, NAN}) {
+ EXPECT_RESULT(Result::INVALID_ARGUMENTS, setGain(value)) << "value=" << value;
+ }
+ // Do not consider -0.0 as an invalid value as it is == with 0.0
+ for (float value : {-0.0, 0.0, 0.01, 0.5, 0.09, 1.0 /* Restore volume*/}) {
+ EXPECT_OK(setGain(value)) << "value=" << value;
+ }
+}
+
+static void testOptionalUnitaryGain(std::function<Return<Result>(float)> setGain,
+ string debugName) {
+ auto result = setGain(1);
+ ASSERT_IS_OK(result);
+ if (result == Result::NOT_SUPPORTED) {
+ doc::partialTest(debugName + " is not supported");
+ return;
+ }
+ testUnitaryGain(setGain);
+}
+
+TEST_P(InputStreamTest, SetGain) {
+ doc::test("The gain of an input stream should only be set between [0,1]");
+ testOptionalUnitaryGain([this](float volume) { return stream->setGain(volume); },
+ "InputStream::setGain");
+}
+
+static void testPrepareForReading(IStreamIn* stream, uint32_t frameSize, uint32_t framesCount) {
+ Result res;
+ // Ignore output parameters as the call should fail
+ ASSERT_OK(stream->prepareForReading(frameSize, framesCount,
+ [&res](auto r, auto&, auto&, auto&, auto&) { res = r; }));
+ EXPECT_RESULT(Result::INVALID_ARGUMENTS, res);
+}
+
+TEST_P(InputStreamTest, PrepareForReadingWithZeroBuffer) {
+ doc::test("Preparing a stream for reading with a 0 sized buffer should fail");
+ testPrepareForReading(stream.get(), 0, 0);
+}
+
+TEST_P(InputStreamTest, PrepareForReadingWithHugeBuffer) {
+ doc::test("Preparing a stream for reading with a 2^32 sized buffer should fail");
+ testPrepareForReading(stream.get(), 1, std::numeric_limits<uint32_t>::max());
+}
+
+TEST_P(InputStreamTest, PrepareForReadingCheckOverflow) {
+ doc::test(
+ "Preparing a stream for reading with a overflowing sized buffer should "
+ "fail");
+ auto uintMax = std::numeric_limits<uint32_t>::max();
+ testPrepareForReading(stream.get(), uintMax, uintMax);
+}
+
+TEST_P(InputStreamTest, GetInputFramesLost) {
+ doc::test("The number of frames lost on a never started stream should be 0");
+ auto ret = stream->getInputFramesLost();
+ ASSERT_IS_OK(ret);
+ uint32_t framesLost{ret};
+ ASSERT_EQ(0U, framesLost);
+}
+
+TEST_P(InputStreamTest, getCapturePosition) {
+ doc::test(
+ "The capture position of a non prepared stream should not be "
+ "retrievable");
+ uint64_t frames;
+ uint64_t time;
+ ASSERT_OK(stream->getCapturePosition(returnIn(res, frames, time)));
+ ASSERT_RESULT(invalidStateOrNotSupported, res);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+///////////////////////////////// StreamIn ///////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_P(OutputStreamTest, getLatency) {
+ doc::test("Make sure latency is over 0");
+ auto result = stream->getLatency();
+ ASSERT_IS_OK(result);
+ ASSERT_GT(result, 0U);
+}
+
+TEST_P(OutputStreamTest, setVolume) {
+ doc::test("Try to set the output volume");
+ testOptionalUnitaryGain([this](float volume) { return stream->setVolume(volume, volume); },
+ "setVolume");
+}
+
+static void testPrepareForWriting(IStreamOut* stream, uint32_t frameSize, uint32_t framesCount) {
+ Result res;
+ // Ignore output parameters as the call should fail
+ ASSERT_OK(stream->prepareForWriting(frameSize, framesCount,
+ [&res](auto r, auto&, auto&, auto&, auto&) { res = r; }));
+ EXPECT_RESULT(Result::INVALID_ARGUMENTS, res);
+}
+
+TEST_P(OutputStreamTest, PrepareForWriteWithZeroBuffer) {
+ doc::test("Preparing a stream for writing with a 0 sized buffer should fail");
+ testPrepareForWriting(stream.get(), 0, 0);
+}
+
+TEST_P(OutputStreamTest, PrepareForWriteWithHugeBuffer) {
+ doc::test("Preparing a stream for writing with a 2^32 sized buffer should fail");
+ testPrepareForWriting(stream.get(), 1, std::numeric_limits<uint32_t>::max());
+}
+
+TEST_P(OutputStreamTest, PrepareForWritingCheckOverflow) {
+ doc::test(
+ "Preparing a stream for writing with a overflowing sized buffer should "
+ "fail");
+ auto uintMax = std::numeric_limits<uint32_t>::max();
+ testPrepareForWriting(stream.get(), uintMax, uintMax);
+}
+
+struct Capability {
+ Capability(IStreamOut* stream) {
+ EXPECT_OK(stream->supportsPauseAndResume(returnIn(pause, resume)));
+ auto ret = stream->supportsDrain();
+ EXPECT_IS_OK(ret);
+ if (ret.isOk()) {
+ drain = ret;
+ }
+ }
+ bool pause = false;
+ bool resume = false;
+ bool drain = false;
+};
+
+TEST_P(OutputStreamTest, SupportsPauseAndResumeAndDrain) {
+ doc::test("Implementation must expose pause, resume and drain capabilities");
+ Capability(stream.get());
+}
+
+template <class Value>
+static void checkInvalidStateOr0(Result res, Value value) {
+ switch (res) {
+ case Result::INVALID_STATE:
+ break;
+ case Result::OK:
+ ASSERT_EQ(0U, value);
+ break;
+ default:
+ FAIL() << "Unexpected result " << toString(res);
+ }
+}
+
+TEST_P(OutputStreamTest, GetRenderPosition) {
+ doc::test("A new stream render position should be 0 or INVALID_STATE");
+ uint32_t dspFrames;
+ ASSERT_OK(stream->getRenderPosition(returnIn(res, dspFrames)));
+ if (res == Result::NOT_SUPPORTED) {
+ doc::partialTest("getRenderPosition is not supported");
+ return;
+ }
+ checkInvalidStateOr0(res, dspFrames);
+}
+
+TEST_P(OutputStreamTest, GetNextWriteTimestamp) {
+ doc::test("A new stream next write timestamp should be 0 or INVALID_STATE");
+ uint64_t timestampUs;
+ ASSERT_OK(stream->getNextWriteTimestamp(returnIn(res, timestampUs)));
+ if (res == Result::NOT_SUPPORTED) {
+ doc::partialTest("getNextWriteTimestamp is not supported");
+ return;
+ }
+ checkInvalidStateOr0(res, timestampUs);
+}
+
+/** Stub implementation of out stream callback. */
+class MockOutCallbacks : public IStreamOutCallback {
+ Return<void> onWriteReady() override { return {}; }
+ Return<void> onDrainReady() override { return {}; }
+ Return<void> onError() override { return {}; }
+};
+
+static bool isAsyncModeSupported(IStreamOut* stream) {
+ auto res = stream->setCallback(new MockOutCallbacks);
+ stream->clearCallback(); // try to restore the no callback state, ignore
+ // any error
+ auto okOrNotSupported = {Result::OK, Result::NOT_SUPPORTED};
+ EXPECT_RESULT(okOrNotSupported, res);
+ return res.isOk() ? res == Result::OK : false;
+}
+
+TEST_P(OutputStreamTest, SetCallback) {
+ doc::test(
+ "If supported, registering callback for async operation should never "
+ "fail");
+ if (!isAsyncModeSupported(stream.get())) {
+ doc::partialTest("The stream does not support async operations");
+ return;
+ }
+ ASSERT_OK(stream->setCallback(new MockOutCallbacks));
+ ASSERT_OK(stream->setCallback(new MockOutCallbacks));
+}
+
+TEST_P(OutputStreamTest, clearCallback) {
+ doc::test(
+ "If supported, clearing a callback to go back to sync operation should "
+ "not fail");
+ if (!isAsyncModeSupported(stream.get())) {
+ doc::partialTest("The stream does not support async operations");
+ return;
+ }
+ // TODO: Clarify if clearing a non existing callback should fail
+ ASSERT_OK(stream->setCallback(new MockOutCallbacks));
+ ASSERT_OK(stream->clearCallback());
+}
+
+TEST_P(OutputStreamTest, Resume) {
+ doc::test(
+ "If supported, a stream should fail to resume if not previously "
+ "paused");
+ if (!Capability(stream.get()).resume) {
+ doc::partialTest("The output stream does not support resume");
+ return;
+ }
+ ASSERT_RESULT(Result::INVALID_STATE, stream->resume());
+}
+
+TEST_P(OutputStreamTest, Pause) {
+ doc::test(
+ "If supported, a stream should fail to pause if not previously "
+ "started");
+ if (!Capability(stream.get()).pause) {
+ doc::partialTest("The output stream does not support pause");
+ return;
+ }
+ ASSERT_RESULT(Result::INVALID_STATE, stream->resume());
+}
+
+static void testDrain(IStreamOut* stream, AudioDrain type) {
+ if (!Capability(stream).drain) {
+ doc::partialTest("The output stream does not support drain");
+ return;
+ }
+ ASSERT_RESULT(Result::OK, stream->drain(type));
+}
+
+TEST_P(OutputStreamTest, DrainAll) {
+ doc::test("If supported, a stream should always succeed to drain");
+ testDrain(stream.get(), AudioDrain::ALL);
+}
+
+TEST_P(OutputStreamTest, DrainEarlyNotify) {
+ doc::test("If supported, a stream should always succeed to drain");
+ testDrain(stream.get(), AudioDrain::EARLY_NOTIFY);
+}
+
+TEST_P(OutputStreamTest, FlushStop) {
+ doc::test("If supported, a stream should always succeed to flush");
+ auto ret = stream->flush();
+ ASSERT_IS_OK(ret);
+ if (ret == Result::NOT_SUPPORTED) {
+ doc::partialTest("Flush is not supported");
+ return;
+ }
+ ASSERT_OK(ret);
+}
+
+TEST_P(OutputStreamTest, GetPresentationPositionStop) {
+ doc::test(
+ "If supported, a stream should always succeed to retrieve the "
+ "presentation position");
+ uint64_t frames;
+ TimeSpec mesureTS;
+ ASSERT_OK(stream->getPresentationPosition(returnIn(res, frames, mesureTS)));
+ if (res == Result::NOT_SUPPORTED) {
+ doc::partialTest("getpresentationPosition is not supported");
+ return;
+ }
+ ASSERT_EQ(0U, frames);
+
+ if (mesureTS.tvNSec == 0 && mesureTS.tvSec == 0) {
+ // As the stream has never written a frame yet,
+ // the timestamp does not really have a meaning, allow to return 0
+ return;
+ }
+
+ // Make sure the return measure is not more than 1s old.
+ struct timespec currentTS;
+ ASSERT_EQ(0, clock_gettime(CLOCK_MONOTONIC, ¤tTS)) << errno;
+
+ auto toMicroSec = [](uint64_t sec, auto nsec) { return sec * 1e+6 + nsec / 1e+3; };
+ auto currentTime = toMicroSec(currentTS.tv_sec, currentTS.tv_nsec);
+ auto mesureTime = toMicroSec(mesureTS.tvSec, mesureTS.tvNSec);
+ ASSERT_PRED2([](auto c, auto m) { return c - m < 1e+6; }, currentTime, mesureTime);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+/////////////////////////////// PrimaryDevice ////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+TEST_F(AudioPrimaryHidlTest, setVoiceVolume) {
+ doc::test("Make sure setVoiceVolume only succeed if volume is in [0,1]");
+ testUnitaryGain([](float volume) { return device->setVoiceVolume(volume); });
+}
+
+TEST_F(AudioPrimaryHidlTest, setMode) {
+ doc::test(
+ "Make sure setMode always succeeds if mode is valid "
+ "and fails otherwise");
+ // Test Invalid values
+ for (int mode : {-1, 0, int(AudioMode::IN_COMMUNICATION) + 1}) {
+ SCOPED_TRACE("mode=" + to_string(mode));
+ ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(AudioMode(mode)));
+ }
+ // Test valid values
+ for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE,
+ AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) {
+ SCOPED_TRACE("mode=" + toString(mode));
+ ASSERT_OK(device->setMode(mode));
+ }
+}
+
+TEST_F(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) {
+ doc::test("Query and set the BT SCO NR&EC state");
+ testOptionalAccessors("BtScoNrecEnabled", {true, false, true},
+ &IPrimaryDevice::setBtScoNrecEnabled,
+ &IPrimaryDevice::getBtScoNrecEnabled);
+}
+
+TEST_F(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) {
+ doc::test("Query and set the SCO whideband state");
+ testOptionalAccessors("BtScoWideband", {true, false, true},
+ &IPrimaryDevice::setBtScoWidebandEnabled,
+ &IPrimaryDevice::getBtScoWidebandEnabled);
+}
+
+using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<TtyMode>;
+TEST_F(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) {
+ doc::test("Query and set the TTY mode state");
+ testOptionalAccessors("TTY mode", {TtyMode::OFF, TtyMode::HCO, TtyMode::VCO, TtyMode::FULL},
+ &IPrimaryDevice::setTtyMode, &IPrimaryDevice::getTtyMode);
+}
+
+TEST_F(BoolAccessorPrimaryHidlTest, setGetHac) {
+ doc::test("Query and set the HAC state");
+ testOptionalAccessors("HAC", {true, false, true}, &IPrimaryDevice::setHacEnabled,
+ &IPrimaryDevice::getHacEnabled);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////// Clean caches on global tear down ////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+int main(int argc, char** argv) {
+ environment = new AudioHidlTestEnvironment;
+ ::testing::AddGlobalTestEnvironment(environment);
+ ::testing::InitGoogleTest(&argc, argv);
+ environment->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ return status;
+}
diff --git a/audio/core/4.0/vts/functional/ValidateAudioConfiguration.cpp b/audio/core/4.0/vts/functional/ValidateAudioConfiguration.cpp
new file mode 100644
index 0000000..a64513f
--- /dev/null
+++ b/audio/core/4.0/vts/functional/ValidateAudioConfiguration.cpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 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 <unistd.h>
+#include <string>
+
+#include "utility/ValidateXml.h"
+
+TEST(CheckConfig, audioPolicyConfigurationValidation) {
+ RecordProperty("description",
+ "Verify that the audio policy configuration file "
+ "is valid according to the schema");
+
+ std::vector<const char*> locations = {"/odm/etc", "/vendor/etc", "/system/etc"};
+ EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS("audio_policy_configuration.xml", locations,
+ "/data/local/tmp/audio_policy_configuration_V4_0.xsd");
+}
diff --git a/audio/effect/4.0/vts/OWNERS b/audio/effect/4.0/vts/OWNERS
new file mode 100644
index 0000000..8711a9f
--- /dev/null
+++ b/audio/effect/4.0/vts/OWNERS
@@ -0,0 +1,5 @@
+elaurent@google.com
+krocard@google.com
+mnaganov@google.com
+yim@google.com
+zhuoyao@google.com
\ No newline at end of file
diff --git a/audio/effect/4.0/vts/functional/Android.bp b/audio/effect/4.0/vts/functional/Android.bp
new file mode 100644
index 0000000..92b5db7
--- /dev/null
+++ b/audio/effect/4.0/vts/functional/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2016 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.
+//
+
+cc_test {
+ name: "VtsHalAudioEffectV4_0TargetTest",
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "VtsHalAudioEffectV4_0TargetTest.cpp",
+ "ValidateAudioEffectsConfiguration.cpp"
+ ],
+ static_libs: [
+ "android.hardware.audio.common.test.utility",
+ "android.hardware.audio.common@4.0",
+ "android.hardware.audio.effect@4.0",
+ "android.hidl.allocator@1.0",
+ "android.hidl.memory@1.0",
+ "libxml2",
+ ],
+ shared_libs: [
+ "libeffectsconfig",
+ "libicuuc",
+ ],
+ header_libs: [
+ "android.hardware.audio.common.util@all-versions",
+ ],
+}
diff --git a/audio/effect/4.0/vts/functional/ValidateAudioEffectsConfiguration.cpp b/audio/effect/4.0/vts/functional/ValidateAudioEffectsConfiguration.cpp
new file mode 100644
index 0000000..6338563
--- /dev/null
+++ b/audio/effect/4.0/vts/functional/ValidateAudioEffectsConfiguration.cpp
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2017 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 <unistd.h>
+#include <iterator>
+
+#include <media/EffectsConfig.h>
+
+#include "utility/ValidateXml.h"
+
+TEST(CheckConfig, audioEffectsConfigurationValidation) {
+ RecordProperty("description",
+ "Verify that the effects configuration file is valid according to the schema");
+ using namespace android::effectsConfig;
+
+ std::vector<const char*> locations(std::begin(DEFAULT_LOCATIONS), std::end(DEFAULT_LOCATIONS));
+ EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(DEFAULT_NAME, locations,
+ "/data/local/tmp/audio_effects_conf_V4_0.xsd");
+}
diff --git a/audio/effect/4.0/vts/functional/VtsHalAudioEffectV4_0TargetTest.cpp b/audio/effect/4.0/vts/functional/VtsHalAudioEffectV4_0TargetTest.cpp
new file mode 100644
index 0000000..ec783c4
--- /dev/null
+++ b/audio/effect/4.0/vts/functional/VtsHalAudioEffectV4_0TargetTest.cpp
@@ -0,0 +1,852 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioEffectHidlHalTest"
+#include <android-base/logging.h>
+#include <system/audio.h>
+
+#include <android/hardware/audio/effect/4.0/IEffect.h>
+#include <android/hardware/audio/effect/4.0/IEffectsFactory.h>
+#include <android/hardware/audio/effect/4.0/IEqualizerEffect.h>
+#include <android/hardware/audio/effect/4.0/ILoudnessEnhancerEffect.h>
+#include <android/hardware/audio/effect/4.0/types.h>
+#include <android/hidl/allocator/1.0/IAllocator.h>
+#include <android/hidl/memory/1.0/IMemory.h>
+
+#include <common/all-versions/VersionUtils.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+
+using android::hardware::audio::common::V4_0::AudioDevice;
+using android::hardware::audio::common::V4_0::AudioHandleConsts;
+using android::hardware::audio::common::V4_0::AudioMode;
+using android::hardware::audio::common::V4_0::AudioSource;
+using android::hardware::audio::common::V4_0::Uuid;
+using android::hardware::audio::common::utils::mkBitfield;
+using android::hardware::audio::effect::V4_0::AudioBuffer;
+using android::hardware::audio::effect::V4_0::EffectAuxChannelsConfig;
+using android::hardware::audio::effect::V4_0::EffectBufferConfig;
+using android::hardware::audio::effect::V4_0::EffectConfig;
+using android::hardware::audio::effect::V4_0::EffectDescriptor;
+using android::hardware::audio::effect::V4_0::EffectOffloadParameter;
+using android::hardware::audio::effect::V4_0::IEffect;
+using android::hardware::audio::effect::V4_0::IEffectsFactory;
+using android::hardware::audio::effect::V4_0::IEqualizerEffect;
+using android::hardware::audio::effect::V4_0::ILoudnessEnhancerEffect;
+using android::hardware::audio::effect::V4_0::Result;
+using android::hardware::MQDescriptorSync;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::hidl_handle;
+using android::hardware::hidl_memory;
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+using android::hidl::allocator::V1_0::IAllocator;
+using android::hidl::memory::V1_0::IMemory;
+using android::sp;
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+#endif
+
+// Test environment for Audio Effects Factory HIDL HAL.
+class AudioEffectsFactoryHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+ public:
+ // get the test environment singleton
+ static AudioEffectsFactoryHidlEnvironment* Instance() {
+ static AudioEffectsFactoryHidlEnvironment* instance =
+ new AudioEffectsFactoryHidlEnvironment;
+ return instance;
+ }
+
+ virtual void registerTestServices() override { registerTestService<IEffectsFactory>(); }
+};
+
+// The main test class for Audio Effects Factory HIDL HAL.
+class AudioEffectsFactoryHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ void SetUp() override {
+ effectsFactory = ::testing::VtsHalHidlTargetTestBase::getService<IEffectsFactory>(
+ AudioEffectsFactoryHidlEnvironment::Instance()->getServiceName<IEffectsFactory>());
+ ASSERT_NE(effectsFactory, nullptr);
+ }
+
+ void TearDown() override { effectsFactory.clear(); }
+
+ protected:
+ static void description(const std::string& description) {
+ RecordProperty("description", description);
+ }
+
+ sp<IEffectsFactory> effectsFactory;
+};
+
+TEST_F(AudioEffectsFactoryHidlTest, EnumerateEffects) {
+ description("Verify that EnumerateEffects returns at least one effect");
+ Result retval = Result::NOT_INITIALIZED;
+ size_t effectCount = 0;
+ Return<void> ret = effectsFactory->getAllDescriptors(
+ [&](Result r, const hidl_vec<EffectDescriptor>& result) {
+ retval = r;
+ effectCount = result.size();
+ });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_GT(effectCount, 0u);
+}
+
+TEST_F(AudioEffectsFactoryHidlTest, CreateEffect) {
+ description("Verify that an effect can be created via CreateEffect");
+ bool gotEffect = false;
+ Uuid effectUuid;
+ Return<void> ret = effectsFactory->getAllDescriptors(
+ [&](Result r, const hidl_vec<EffectDescriptor>& result) {
+ if (r == Result::OK && result.size() > 0) {
+ gotEffect = true;
+ effectUuid = result[0].uuid;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_TRUE(gotEffect);
+ Result retval = Result::NOT_INITIALIZED;
+ sp<IEffect> effect;
+ ret = effectsFactory->createEffect(
+ effectUuid, 1 /*session*/, 1 /*ioHandle*/,
+ [&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) {
+ retval = r;
+ if (r == Result::OK) {
+ effect = result;
+ }
+ });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_NE(nullptr, effect.get());
+}
+
+TEST_F(AudioEffectsFactoryHidlTest, GetDescriptor) {
+ description(
+ "Verify that effects factory can provide an effect descriptor via "
+ "GetDescriptor");
+ hidl_vec<EffectDescriptor> allDescriptors;
+ Return<void> ret = effectsFactory->getAllDescriptors(
+ [&](Result r, const hidl_vec<EffectDescriptor>& result) {
+ if (r == Result::OK) {
+ allDescriptors = result;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_GT(allDescriptors.size(), 0u);
+ for (size_t i = 0; i < allDescriptors.size(); ++i) {
+ ret = effectsFactory->getDescriptor(
+ allDescriptors[i].uuid, [&](Result r, const EffectDescriptor& result) {
+ EXPECT_EQ(r, Result::OK);
+ EXPECT_EQ(result, allDescriptors[i]);
+ });
+ }
+ EXPECT_TRUE(ret.isOk());
+}
+
+TEST_F(AudioEffectsFactoryHidlTest, DebugDumpInvalidArgument) {
+ description("Verify that debugDump doesn't crash on invalid arguments");
+ Return<void> ret = effectsFactory->debug(hidl_handle(), {});
+ ASSERT_TRUE(ret.isOk());
+}
+
+// Equalizer effect is required by CDD, but only the type is fixed.
+// This is the same UUID as AudioEffect.EFFECT_TYPE_EQUALIZER in Java.
+static const Uuid EQUALIZER_EFFECT_TYPE = {
+ 0x0bed4300, 0xddd6, 0x11db, 0x8f34,
+ std::array<uint8_t, 6>{{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}};
+// Loudness Enhancer effect is required by CDD, but only the type is fixed.
+// This is the same UUID as AudioEffect.EFFECT_TYPE_LOUDNESS_ENHANCER in Java.
+static const Uuid LOUDNESS_ENHANCER_EFFECT_TYPE = {
+ 0xfe3199be, 0xaed0, 0x413f, 0x87bb,
+ std::array<uint8_t, 6>{{0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}}};
+
+// The main test class for Audio Effect HIDL HAL.
+class AudioEffectHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+ public:
+ void SetUp() override {
+ effectsFactory =
+ ::testing::VtsHalHidlTargetTestBase::getService<IEffectsFactory>();
+ ASSERT_NE(nullptr, effectsFactory.get());
+
+ findAndCreateEffect(getEffectType());
+ ASSERT_NE(nullptr, effect.get());
+
+ Return<Result> ret = effect->init();
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, ret);
+ }
+
+ void TearDown() override {
+ effect.clear();
+ effectsFactory.clear();
+ }
+
+ protected:
+ static void description(const std::string& description) {
+ RecordProperty("description", description);
+ }
+
+ virtual Uuid getEffectType() { return EQUALIZER_EFFECT_TYPE; }
+
+ void findAndCreateEffect(const Uuid& type);
+ void findEffectInstance(const Uuid& type, Uuid* uuid);
+ void getChannelCount(uint32_t* channelCount);
+
+ sp<IEffectsFactory> effectsFactory;
+ sp<IEffect> effect;
+};
+
+void AudioEffectHidlTest::findAndCreateEffect(const Uuid& type) {
+ Uuid effectUuid;
+ findEffectInstance(type, &effectUuid);
+ Return<void> ret = effectsFactory->createEffect(
+ effectUuid, 1 /*session*/, 1 /*ioHandle*/,
+ [&](Result r, const sp<IEffect>& result, uint64_t /*effectId*/) {
+ if (r == Result::OK) {
+ effect = result;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+}
+
+void AudioEffectHidlTest::findEffectInstance(const Uuid& type, Uuid* uuid) {
+ bool effectFound = false;
+ Return<void> ret = effectsFactory->getAllDescriptors(
+ [&](Result r, const hidl_vec<EffectDescriptor>& result) {
+ if (r == Result::OK) {
+ for (const auto& desc : result) {
+ if (desc.type == type) {
+ effectFound = true;
+ *uuid = desc.uuid;
+ break;
+ }
+ }
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_TRUE(effectFound);
+}
+
+void AudioEffectHidlTest::getChannelCount(uint32_t* channelCount) {
+ Result retval;
+ EffectConfig currentConfig;
+ Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) {
+ retval = r;
+ if (r == Result::OK) {
+ currentConfig = conf;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, retval);
+ ASSERT_TRUE(audio_channel_mask_is_valid(
+ static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels)));
+ *channelCount = audio_channel_count_from_out_mask(
+ static_cast<audio_channel_mask_t>(currentConfig.outputCfg.channels));
+}
+
+TEST_F(AudioEffectHidlTest, Close) {
+ description("Verify that an effect can be closed");
+ Return<Result> ret = effect->close();
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+}
+
+TEST_F(AudioEffectHidlTest, GetDescriptor) {
+ description(
+ "Verify that an effect can return its own descriptor via GetDescriptor");
+ Result retval = Result::NOT_INITIALIZED;
+ Uuid actualType;
+ Return<void> ret =
+ effect->getDescriptor([&](Result r, const EffectDescriptor& desc) {
+ retval = r;
+ if (r == Result::OK) {
+ actualType = desc.type;
+ }
+ });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_EQ(getEffectType(), actualType);
+}
+
+TEST_F(AudioEffectHidlTest, GetSetConfig) {
+ description(
+ "Verify that it is possible to manipulate effect config via Get / "
+ "SetConfig");
+ Result retval = Result::NOT_INITIALIZED;
+ EffectConfig currentConfig;
+ Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) {
+ retval = r;
+ if (r == Result::OK) {
+ currentConfig = conf;
+ }
+ });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ Return<Result> ret2 = effect->setConfig(currentConfig, nullptr, nullptr);
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, ret2);
+}
+
+TEST_F(AudioEffectHidlTest, GetConfigReverse) {
+ description("Verify that GetConfigReverse does not crash");
+ Return<void> ret =
+ effect->getConfigReverse([&](Result, const EffectConfig&) {});
+ EXPECT_TRUE(ret.isOk());
+}
+
+TEST_F(AudioEffectHidlTest, GetSupportedAuxChannelsConfigs) {
+ description("Verify that GetSupportedAuxChannelsConfigs does not crash");
+ Return<void> ret = effect->getSupportedAuxChannelsConfigs(
+ 0, [&](Result, const hidl_vec<EffectAuxChannelsConfig>&) {});
+ EXPECT_TRUE(ret.isOk());
+}
+
+TEST_F(AudioEffectHidlTest, GetAuxChannelsConfig) {
+ description("Verify that GetAuxChannelsConfig does not crash");
+ Return<void> ret = effect->getAuxChannelsConfig(
+ [&](Result, const EffectAuxChannelsConfig&) {});
+ EXPECT_TRUE(ret.isOk());
+}
+
+TEST_F(AudioEffectHidlTest, SetAuxChannelsConfig) {
+ description("Verify that SetAuxChannelsConfig does not crash");
+ Return<Result> ret = effect->setAuxChannelsConfig(EffectAuxChannelsConfig());
+ EXPECT_TRUE(ret.isOk());
+}
+
+// Not generated automatically because AudioBuffer contains
+// instances of hidl_memory which can't be compared properly
+// in general case due to presence of handles.
+//
+// However, in this particular case, handles must not present
+// thus comparison is possible.
+//
+// operator== must be defined in the same namespace as the structures.
+namespace android {
+namespace hardware {
+namespace audio {
+namespace effect {
+namespace V4_0 {
+inline bool operator==(const AudioBuffer& lhs, const AudioBuffer& rhs) {
+ return lhs.id == rhs.id && lhs.frameCount == rhs.frameCount &&
+ lhs.data.handle() == nullptr && rhs.data.handle() == nullptr;
+}
+
+inline bool operator==(const EffectBufferConfig& lhs,
+ const EffectBufferConfig& rhs) {
+ return lhs.buffer == rhs.buffer && lhs.samplingRateHz == rhs.samplingRateHz &&
+ lhs.channels == rhs.channels && lhs.format == rhs.format &&
+ lhs.accessMode == rhs.accessMode && lhs.mask == rhs.mask;
+}
+
+inline bool operator==(const EffectConfig& lhs, const EffectConfig& rhs) {
+ return lhs.inputCfg == rhs.inputCfg && lhs.outputCfg == rhs.outputCfg;
+}
+} // namespace V4_0
+} // namespace effect
+} // namespace audio
+} // namespace hardware
+} // namespace android
+
+TEST_F(AudioEffectHidlTest, Reset) {
+ description("Verify that Reset preserves effect configuration");
+ Result retval = Result::NOT_INITIALIZED;
+ EffectConfig originalConfig;
+ Return<void> ret = effect->getConfig([&](Result r, const EffectConfig& conf) {
+ retval = r;
+ if (r == Result::OK) {
+ originalConfig = conf;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, retval);
+ Return<Result> ret2 = effect->reset();
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, ret2);
+ EffectConfig configAfterReset;
+ ret = effect->getConfig([&](Result r, const EffectConfig& conf) {
+ retval = r;
+ if (r == Result::OK) {
+ configAfterReset = conf;
+ }
+ });
+ EXPECT_EQ(originalConfig, configAfterReset);
+}
+
+TEST_F(AudioEffectHidlTest, DisableEnableDisable) {
+ description("Verify Disable -> Enable -> Disable sequence for an effect");
+ Return<Result> ret = effect->disable();
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::INVALID_ARGUMENTS, ret);
+ ret = effect->enable();
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+ ret = effect->disable();
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+}
+
+TEST_F(AudioEffectHidlTest, SetDevice) {
+ description("Verify that SetDevice works for an output chain effect");
+ Return<Result> ret = effect->setDevice(mkBitfield(AudioDevice::OUT_SPEAKER));
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+}
+
+TEST_F(AudioEffectHidlTest, SetAndGetVolume) {
+ description("Verify that SetAndGetVolume method works for an effect");
+ uint32_t channelCount;
+ getChannelCount(&channelCount);
+ hidl_vec<uint32_t> volumes;
+ volumes.resize(channelCount);
+ for (uint32_t i = 0; i < channelCount; ++i) {
+ volumes[i] = 0;
+ }
+ Result retval = Result::NOT_INITIALIZED;
+ Return<void> ret = effect->setAndGetVolume(
+ volumes, [&](Result r, const hidl_vec<uint32_t>&) { retval = r; });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, retval);
+}
+
+TEST_F(AudioEffectHidlTest, VolumeChangeNotification) {
+ description("Verify that effect accepts VolumeChangeNotification");
+ uint32_t channelCount;
+ getChannelCount(&channelCount);
+ hidl_vec<uint32_t> volumes;
+ volumes.resize(channelCount);
+ for (uint32_t i = 0; i < channelCount; ++i) {
+ volumes[i] = 0;
+ }
+ Return<Result> ret = effect->volumeChangeNotification(volumes);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+}
+
+TEST_F(AudioEffectHidlTest, SetAudioMode) {
+ description("Verify that SetAudioMode works for an effect");
+ Return<Result> ret = effect->setAudioMode(AudioMode::NORMAL);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+}
+
+TEST_F(AudioEffectHidlTest, SetConfigReverse) {
+ description("Verify that SetConfigReverse does not crash");
+ Return<Result> ret =
+ effect->setConfigReverse(EffectConfig(), nullptr, nullptr);
+ EXPECT_TRUE(ret.isOk());
+}
+
+TEST_F(AudioEffectHidlTest, SetInputDevice) {
+ description("Verify that SetInputDevice does not crash");
+ Return<Result> ret = effect->setInputDevice(mkBitfield(AudioDevice::IN_BUILTIN_MIC));
+ EXPECT_TRUE(ret.isOk());
+}
+
+TEST_F(AudioEffectHidlTest, SetAudioSource) {
+ description("Verify that SetAudioSource does not crash");
+ Return<Result> ret = effect->setAudioSource(AudioSource::MIC);
+ EXPECT_TRUE(ret.isOk());
+}
+
+TEST_F(AudioEffectHidlTest, Offload) {
+ description("Verify that calling Offload method does not crash");
+ EffectOffloadParameter offloadParam;
+ offloadParam.isOffload = false;
+ offloadParam.ioHandle =
+ static_cast<int>(AudioHandleConsts::AUDIO_IO_HANDLE_NONE);
+ Return<Result> ret = effect->offload(offloadParam);
+ EXPECT_TRUE(ret.isOk());
+}
+
+TEST_F(AudioEffectHidlTest, PrepareForProcessing) {
+ description("Verify that PrepareForProcessing method works for an effect");
+ Result retval = Result::NOT_INITIALIZED;
+ Return<void> ret = effect->prepareForProcessing(
+ [&](Result r, const MQDescriptorSync<Result>&) { retval = r; });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, retval);
+}
+
+TEST_F(AudioEffectHidlTest, SetProcessBuffers) {
+ description("Verify that SetProcessBuffers works for an effect");
+ sp<IAllocator> ashmem = IAllocator::getService("ashmem");
+ ASSERT_NE(nullptr, ashmem.get());
+ bool success = false;
+ AudioBuffer buffer;
+ Return<void> ret =
+ ashmem->allocate(1024, [&](bool s, const hidl_memory& memory) {
+ success = s;
+ if (s) {
+ buffer.data = memory;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_TRUE(success);
+ Return<Result> ret2 = effect->setProcessBuffers(buffer, buffer);
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, ret2);
+}
+
+TEST_F(AudioEffectHidlTest, Command) {
+ description("Verify that Command does not crash");
+ Return<void> ret = effect->command(0, hidl_vec<uint8_t>(), 0,
+ [&](int32_t, const hidl_vec<uint8_t>&) {});
+ EXPECT_TRUE(ret.isOk());
+}
+
+TEST_F(AudioEffectHidlTest, SetParameter) {
+ description("Verify that SetParameter does not crash");
+ Return<Result> ret =
+ effect->setParameter(hidl_vec<uint8_t>(), hidl_vec<uint8_t>());
+ EXPECT_TRUE(ret.isOk());
+}
+
+TEST_F(AudioEffectHidlTest, GetParameter) {
+ description("Verify that GetParameter does not crash");
+ Return<void> ret = effect->getParameter(
+ hidl_vec<uint8_t>(), 0, [&](Result, const hidl_vec<uint8_t>&) {});
+ EXPECT_TRUE(ret.isOk());
+}
+
+TEST_F(AudioEffectHidlTest, GetSupportedConfigsForFeature) {
+ description("Verify that GetSupportedConfigsForFeature does not crash");
+ Return<void> ret = effect->getSupportedConfigsForFeature(
+ 0, 0, 0, [&](Result, uint32_t, const hidl_vec<uint8_t>&) {});
+ EXPECT_TRUE(ret.isOk());
+}
+
+TEST_F(AudioEffectHidlTest, GetCurrentConfigForFeature) {
+ description("Verify that GetCurrentConfigForFeature does not crash");
+ Return<void> ret = effect->getCurrentConfigForFeature(
+ 0, 0, [&](Result, const hidl_vec<uint8_t>&) {});
+ EXPECT_TRUE(ret.isOk());
+}
+
+TEST_F(AudioEffectHidlTest, SetCurrentConfigForFeature) {
+ description("Verify that SetCurrentConfigForFeature does not crash");
+ Return<Result> ret =
+ effect->setCurrentConfigForFeature(0, hidl_vec<uint8_t>());
+ EXPECT_TRUE(ret.isOk());
+}
+
+
+// The main test class for Equalizer Audio Effect HIDL HAL.
+class EqualizerAudioEffectHidlTest : public AudioEffectHidlTest {
+ public:
+ void SetUp() override {
+ AudioEffectHidlTest::SetUp();
+ equalizer = IEqualizerEffect::castFrom(effect);
+ ASSERT_NE(nullptr, equalizer.get());
+ }
+
+ protected:
+ Uuid getEffectType() override { return EQUALIZER_EFFECT_TYPE; }
+ void getNumBands(uint16_t* numBands);
+ void getLevelRange(int16_t* minLevel, int16_t* maxLevel);
+ void getBandFrequencyRange(uint16_t band, uint32_t* minFreq,
+ uint32_t* centerFreq, uint32_t* maxFreq);
+ void getPresetCount(size_t* count);
+
+ sp<IEqualizerEffect> equalizer;
+};
+
+void EqualizerAudioEffectHidlTest::getNumBands(uint16_t* numBands) {
+ Result retval = Result::NOT_INITIALIZED;
+ Return<void> ret = equalizer->getNumBands([&](Result r, uint16_t b) {
+ retval = r;
+ if (retval == Result::OK) {
+ *numBands = b;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, retval);
+}
+
+void EqualizerAudioEffectHidlTest::getLevelRange(int16_t* minLevel,
+ int16_t* maxLevel) {
+ Result retval = Result::NOT_INITIALIZED;
+ Return<void> ret =
+ equalizer->getLevelRange([&](Result r, int16_t min, int16_t max) {
+ retval = r;
+ if (retval == Result::OK) {
+ *minLevel = min;
+ *maxLevel = max;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, retval);
+}
+
+void EqualizerAudioEffectHidlTest::getBandFrequencyRange(uint16_t band,
+ uint32_t* minFreq,
+ uint32_t* centerFreq,
+ uint32_t* maxFreq) {
+ Result retval = Result::NOT_INITIALIZED;
+ Return<void> ret = equalizer->getBandFrequencyRange(
+ band, [&](Result r, uint32_t min, uint32_t max) {
+ retval = r;
+ if (retval == Result::OK) {
+ *minFreq = min;
+ *maxFreq = max;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, retval);
+ ret = equalizer->getBandCenterFrequency(band, [&](Result r, uint32_t center) {
+ retval = r;
+ if (retval == Result::OK) {
+ *centerFreq = center;
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, retval);
+}
+
+void EqualizerAudioEffectHidlTest::getPresetCount(size_t* count) {
+ Result retval = Result::NOT_INITIALIZED;
+ Return<void> ret = equalizer->getPresetNames(
+ [&](Result r, const hidl_vec<hidl_string>& names) {
+ retval = r;
+ if (retval == Result::OK) {
+ *count = names.size();
+ }
+ });
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(Result::OK, retval);
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetNumBands) {
+ description("Verify that Equalizer effect reports at least one band");
+ uint16_t numBands = 0;
+ getNumBands(&numBands);
+ EXPECT_GT(numBands, 0);
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetLevelRange) {
+ description("Verify that Equalizer effect reports adequate band level range");
+ int16_t minLevel = 0x7fff, maxLevel = 0;
+ getLevelRange(&minLevel, &maxLevel);
+ EXPECT_GT(maxLevel, minLevel);
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetSetBandLevel) {
+ description(
+ "Verify that manipulating band levels works for Equalizer effect");
+ uint16_t numBands = 0;
+ getNumBands(&numBands);
+ ASSERT_GT(numBands, 0);
+ int16_t levels[3]{0x7fff, 0, 0};
+ getLevelRange(&levels[0], &levels[2]);
+ ASSERT_GT(levels[2], levels[0]);
+ levels[1] = (levels[2] + levels[0]) / 2;
+ for (uint16_t i = 0; i < numBands; ++i) {
+ for (size_t j = 0; j < ARRAY_SIZE(levels); ++j) {
+ Return<Result> ret = equalizer->setBandLevel(i, levels[j]);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+ Result retval = Result::NOT_INITIALIZED;
+ int16_t actualLevel;
+ Return<void> ret2 = equalizer->getBandLevel(i, [&](Result r, int16_t l) {
+ retval = r;
+ if (retval == Result::OK) {
+ actualLevel = l;
+ }
+ });
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_EQ(levels[j], actualLevel);
+ }
+ }
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetBandCenterFrequencyAndRange) {
+ description(
+ "Verify that Equalizer effect reports adequate band frequency range");
+ uint16_t numBands = 0;
+ getNumBands(&numBands);
+ ASSERT_GT(numBands, 0);
+ for (uint16_t i = 0; i < numBands; ++i) {
+ uint32_t minFreq = 0xffffffff, centerFreq = 0xffffffff,
+ maxFreq = 0xffffffff;
+ getBandFrequencyRange(i, &minFreq, ¢erFreq, &maxFreq);
+ // Note: NXP legacy implementation reports "1" as upper bound for last band,
+ // so this check fails.
+ EXPECT_GE(maxFreq, centerFreq);
+ EXPECT_GE(centerFreq, minFreq);
+ }
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetBandForFrequency) {
+ description(
+ "Verify that Equalizer effect supports GetBandForFrequency correctly");
+ uint16_t numBands = 0;
+ getNumBands(&numBands);
+ ASSERT_GT(numBands, 0);
+ for (uint16_t i = 0; i < numBands; ++i) {
+ uint32_t freqs[3]{0, 0, 0};
+ getBandFrequencyRange(i, &freqs[0], &freqs[1], &freqs[2]);
+ // NXP legacy implementation reports "1" as upper bound for last band, some
+ // of the checks fail.
+ for (size_t j = 0; j < ARRAY_SIZE(freqs); ++j) {
+ if (j == 0) {
+ freqs[j]++;
+ } // Min frequency is an open interval.
+ Result retval = Result::NOT_INITIALIZED;
+ uint16_t actualBand = numBands + 1;
+ Return<void> ret =
+ equalizer->getBandForFrequency(freqs[j], [&](Result r, uint16_t b) {
+ retval = r;
+ if (retval == Result::OK) {
+ actualBand = b;
+ }
+ });
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_EQ(i, actualBand) << "Frequency: " << freqs[j];
+ }
+ }
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetPresetNames) {
+ description("Verify that Equalizer effect reports at least one preset");
+ size_t presetCount;
+ getPresetCount(&presetCount);
+ EXPECT_GT(presetCount, 0u);
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetSetCurrentPreset) {
+ description(
+ "Verify that manipulating the current preset for Equalizer effect");
+ size_t presetCount;
+ getPresetCount(&presetCount);
+ ASSERT_GT(presetCount, 0u);
+ for (uint16_t i = 0; i < presetCount; ++i) {
+ Return<Result> ret = equalizer->setCurrentPreset(i);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+ Result retval = Result::NOT_INITIALIZED;
+ uint16_t actualPreset = 0xffff;
+ Return<void> ret2 = equalizer->getCurrentPreset([&](Result r, uint16_t p) {
+ retval = r;
+ if (retval == Result::OK) {
+ actualPreset = p;
+ }
+ });
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_EQ(i, actualPreset);
+ }
+}
+
+TEST_F(EqualizerAudioEffectHidlTest, GetSetAllProperties) {
+ description(
+ "Verify that setting band levels and presets works via Get / "
+ "SetAllProperties for Equalizer effect");
+ using AllProperties =
+ android::hardware::audio::effect::V4_0::IEqualizerEffect::AllProperties;
+ uint16_t numBands = 0;
+ getNumBands(&numBands);
+ ASSERT_GT(numBands, 0);
+ AllProperties props;
+ props.bandLevels.resize(numBands);
+ for (size_t i = 0; i < numBands; ++i) {
+ props.bandLevels[i] = 0;
+ }
+
+ AllProperties actualProps;
+ Result retval = Result::NOT_INITIALIZED;
+
+ // Verify setting of the band levels via properties.
+ props.curPreset = -1;
+ Return<Result> ret = equalizer->setAllProperties(props);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+ Return<void> ret2 =
+ equalizer->getAllProperties([&](Result r, AllProperties p) {
+ retval = r;
+ if (retval == Result::OK) {
+ actualProps = p;
+ }
+ });
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_EQ(props.bandLevels, actualProps.bandLevels);
+
+ // Verify setting of the current preset via properties.
+ props.curPreset = 0; // Assuming there is at least one preset.
+ ret = equalizer->setAllProperties(props);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+ ret2 = equalizer->getAllProperties([&](Result r, AllProperties p) {
+ retval = r;
+ if (retval == Result::OK) {
+ actualProps = p;
+ }
+ });
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_EQ(props.curPreset, actualProps.curPreset);
+}
+
+// The main test class for Equalizer Audio Effect HIDL HAL.
+class LoudnessEnhancerAudioEffectHidlTest : public AudioEffectHidlTest {
+ public:
+ void SetUp() override {
+ AudioEffectHidlTest::SetUp();
+ enhancer = ILoudnessEnhancerEffect::castFrom(effect);
+ ASSERT_NE(nullptr, enhancer.get());
+ }
+
+ protected:
+ Uuid getEffectType() override { return LOUDNESS_ENHANCER_EFFECT_TYPE; }
+
+ sp<ILoudnessEnhancerEffect> enhancer;
+};
+
+TEST_F(LoudnessEnhancerAudioEffectHidlTest, GetSetTargetGain) {
+ description(
+ "Verify that manipulating the target gain works for Loudness Enhancer "
+ "effect");
+ const int32_t gain = 100;
+ Return<Result> ret = enhancer->setTargetGain(gain);
+ EXPECT_TRUE(ret.isOk());
+ EXPECT_EQ(Result::OK, ret);
+ int32_t actualGain = 0;
+ Result retval;
+ Return<void> ret2 = enhancer->getTargetGain([&](Result r, int32_t g) {
+ retval = r;
+ if (retval == Result::OK) {
+ actualGain = g;
+ }
+ });
+ EXPECT_TRUE(ret2.isOk());
+ EXPECT_EQ(Result::OK, retval);
+ EXPECT_EQ(gain, actualGain);
+}
+
+int main(int argc, char** argv) {
+ ::testing::AddGlobalTestEnvironment(AudioEffectsFactoryHidlEnvironment::Instance());
+ ::testing::InitGoogleTest(&argc, argv);
+ AudioEffectsFactoryHidlEnvironment::Instance()->init(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}
diff --git a/automotive/vehicle/2.0/Android.bp b/automotive/vehicle/2.0/Android.bp
index bdc44ef..902a4e8 100644
--- a/automotive/vehicle/2.0/Android.bp
+++ b/automotive/vehicle/2.0/Android.bp
@@ -48,6 +48,7 @@
"VehicleHvacFanDirection",
"VehicleHwKeyInputAction",
"VehicleIgnitionState",
+ "VehicleOilLevel",
"VehiclePropConfig",
"VehiclePropValue",
"VehicleProperty",
diff --git a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h
index ce0b163..f97dfa1 100644
--- a/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h
+++ b/automotive/vehicle/2.0/default/common/include/vhal_v2_0/VehicleUtils.h
@@ -33,10 +33,9 @@
constexpr int32_t kAllSupportedAreas = 0;
/** Returns underlying (integer) value for given enum. */
-template<typename ENUM>
-inline constexpr typename std::underlying_type<ENUM>::type toInt(
- ENUM const value) {
- return static_cast<typename std::underlying_type<ENUM>::type>(value);
+template<typename ENUM, typename U = typename std::underlying_type<ENUM>::type>
+inline constexpr U toInt(ENUM const value) {
+ return static_cast<U>(value);
}
inline constexpr VehiclePropertyType getPropType(int32_t prop) {
diff --git a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
index 2c3ebfc..f2aa421 100644
--- a/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
+++ b/automotive/vehicle/2.0/default/common/src/VehiclePropertyStore.cpp
@@ -52,6 +52,7 @@
} else {
valueToUpdate->timestamp = propValue.timestamp;
valueToUpdate->value = propValue.value;
+ valueToUpdate->status = propValue.status;
}
return true;
}
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 c1c511f..e54de00 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
@@ -429,7 +429,7 @@
{.config = {.prop = toInt(VehicleProperty::AP_POWER_BOOTUP_REASON),
.access = VehiclePropertyAccess::READ,
- .changeMode = VehiclePropertyChangeMode::ON_CHANGE},
+ .changeMode = VehiclePropertyChangeMode::STATIC},
.initialValue = {.int32Values = {toInt(VehicleApPowerBootupReason::USER_POWER_ON)}}},
{
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index 764bebd..dc34a50 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -138,6 +138,7 @@
return status;
}
} else if (mHvacPowerProps.count(propValue.prop)) {
+ // TODO(75328113): this should be handled by property status
auto hvacPowerOn = mPropStore->readValueOrNull(
toInt(VehicleProperty::HVAC_POWER_ON),
(VehicleAreaZone::ROW_1_LEFT | VehicleAreaZone::ROW_1_RIGHT));
@@ -165,6 +166,22 @@
}
}
+ if (propValue.status != VehiclePropertyStatus::AVAILABLE) {
+ // Android side cannot set property status - this value is the
+ // purview of the HAL implementation to reflect the state of
+ // its underlying hardware
+ return StatusCode::INVALID_ARG;
+ }
+ auto currentPropValue = mPropStore->readValueOrNull(propValue);
+
+ if (currentPropValue == nullptr) {
+ return StatusCode::INVALID_ARG;
+ }
+ if (currentPropValue->status != VehiclePropertyStatus::AVAILABLE) {
+ // do not allow Android side to set() a disabled/error property
+ return StatusCode::NOT_AVAILABLE;
+ }
+
if (!mPropStore->writeValue(propValue)) {
return StatusCode::INVALID_ARG;
}
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 3001213..87daedc 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -510,6 +510,7 @@
*
* @change_mode VehiclePropertyChangeMode:ON_CHANGE
* @access VehiclePropertyAccess:READ
+ * @data_enum VehicleTurnSignal
*/
TURN_SIGNAL_STATE = (
0x0408
@@ -522,6 +523,7 @@
*
* @change_mode VehiclePropertyChangeMode:ON_CHANGE
* @access VehiclePropertyAccess:READ
+ * @data_enum VehicleIgnitionState
*/
IGNITION_STATE = (
0x0409
diff --git a/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc b/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc
index 123d339..9bfd3ba 100644
--- a/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc
+++ b/biometrics/fingerprint/2.1/default/android.hardware.biometrics.fingerprint@2.1-service.rc
@@ -5,3 +5,4 @@
class late_start
user system
group system input
+ writepid /dev/cpuset/system-background/tasks
\ No newline at end of file
diff --git a/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc b/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc
index e1f5faa..5a01ecc 100644
--- a/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc
+++ b/bluetooth/1.0/default/android.hardware.bluetooth@1.0-service.rc
@@ -1,5 +1,6 @@
service vendor.bluetooth-1-0 /vendor/bin/hw/android.hardware.bluetooth@1.0-service
class hal
+ capabilities NET_ADMIN SYS_NICE
user bluetooth
group bluetooth
writepid /dev/stune/foreground/tasks
diff --git a/camera/common/1.0/default/Exif.cpp b/camera/common/1.0/default/Exif.cpp
index 3e894f9..6054999 100644
--- a/camera/common/1.0/default/Exif.cpp
+++ b/camera/common/1.0/default/Exif.cpp
@@ -983,15 +983,15 @@
camera_metadata_ro_entry entry = metadata.find(ANDROID_LENS_FOCAL_LENGTH);
if (entry.count) {
focal_length = entry.data.f[0];
+
+ if (!setFocalLength(
+ static_cast<uint32_t>(focal_length * kRationalPrecision),
+ kRationalPrecision)) {
+ ALOGE("%s: setting focal length failed.", __FUNCTION__);
+ return false;
+ }
} else {
- ALOGE("%s: Cannot find focal length in metadata.", __FUNCTION__);
- return false;
- }
- if (!setFocalLength(
- static_cast<uint32_t>(focal_length * kRationalPrecision),
- kRationalPrecision)) {
- ALOGE("%s: setting focal length failed.", __FUNCTION__);
- return false;
+ ALOGV("%s: Cannot find focal length in metadata.", __FUNCTION__);
}
if (metadata.exists(ANDROID_JPEG_GPS_COORDINATES)) {
diff --git a/camera/device/3.4/Android.bp b/camera/device/3.4/Android.bp
index 87acd25..2c649ba 100644
--- a/camera/device/3.4/Android.bp
+++ b/camera/device/3.4/Android.bp
@@ -25,7 +25,6 @@
"HalStreamConfiguration",
"PhysicalCameraMetadata",
"PhysicalCameraSetting",
- "RequestTemplate",
"Stream",
"StreamConfiguration",
],
diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp
index 9a02ce8..6b05d4a 100644
--- a/camera/device/3.4/default/ExternalCameraDevice.cpp
+++ b/camera/device/3.4/default/ExternalCameraDevice.cpp
@@ -284,13 +284,6 @@
const int32_t jpegMaxSize = mCfg.maxJpegBufSize;
UPDATE(ANDROID_JPEG_MAX_SIZE, &jpegMaxSize, 1);
- const uint8_t jpegQuality = 90;
- UPDATE(ANDROID_JPEG_QUALITY, &jpegQuality, 1);
- UPDATE(ANDROID_JPEG_THUMBNAIL_QUALITY, &jpegQuality, 1);
-
- const int32_t jpegOrientation = 0;
- UPDATE(ANDROID_JPEG_ORIENTATION, &jpegOrientation, 1);
-
// android.lens
const uint8_t focusDistanceCalibration =
ANDROID_LENS_INFO_FOCUS_DISTANCE_CALIBRATION_UNCALIBRATED;
@@ -322,7 +315,6 @@
// This means pipeline latency of X frame intervals. The maximum number is 4.
const uint8_t requestPipelineMaxDepth = 4;
UPDATE(ANDROID_REQUEST_PIPELINE_MAX_DEPTH, &requestPipelineMaxDepth, 1);
- UPDATE(ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1);
// Three numbers represent the maximum numbers of different types of output
// streams simultaneously. The types are raw sensor, processed (but not
@@ -355,7 +347,6 @@
ANDROID_SENSOR_TEST_PATTERN_MODE_OFF};
UPDATE(ANDROID_SENSOR_AVAILABLE_TEST_PATTERN_MODES, testPatternModes,
ARRAY_SIZE(testPatternModes));
- UPDATE(ANDROID_SENSOR_TEST_PATTERN_MODE, &testPatternModes[0], 1);
const uint8_t timestampSource = ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE_UNKNOWN;
UPDATE(ANDROID_SENSOR_INFO_TIMESTAMP_SOURCE, ×tampSource, 1);
@@ -576,7 +567,6 @@
std::vector<int32_t> streamConfigurations;
std::vector<int64_t> minFrameDurations;
std::vector<int64_t> stallDurations;
- int64_t maxFrameDuration = 0;
int32_t maxFps = std::numeric_limits<int32_t>::min();
int32_t minFps = std::numeric_limits<int32_t>::max();
std::set<int32_t> framerates;
@@ -604,9 +594,6 @@
if (frameDuration < minFrameDuration) {
minFrameDuration = frameDuration;
}
- if (frameDuration > maxFrameDuration) {
- maxFrameDuration = frameDuration;
- }
int32_t frameRateInt = static_cast<int32_t>(fr.getDouble());
if (minFps > frameRateInt) {
minFps = frameRateInt;
@@ -639,14 +626,15 @@
}
std::vector<int32_t> fpsRanges;
- // Variable range
- fpsRanges.push_back(minFps);
- fpsRanges.push_back(maxFps);
- // Fixed ranges
+ // FPS ranges
for (const auto& framerate : framerates) {
- fpsRanges.push_back(framerate);
+ // Empirical: webcams often have close to 2x fps error and cannot support fixed fps range
+ fpsRanges.push_back(framerate / 2);
fpsRanges.push_back(framerate);
}
+ minFps /= 2;
+ int64_t maxFrameDuration = 1000000000LL / minFps;
+
UPDATE(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, fpsRanges.data(),
fpsRanges.size());
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index 5569439..7015bcb 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -47,6 +47,9 @@
const int kBadFramesAfterStreamOn = 1; // drop x frames after streamOn to get rid of some initial
// bad frames. TODO: develop a better bad frame detection
// method
+constexpr int MAX_RETRY = 15; // Allow retry some ioctl failures a few times to account for some
+ // webcam showing temporarily ioctl failures.
+constexpr int IOCTL_RETRY_SLEEP_US = 33000; // 33ms * MAX_RETRY = 5 seconds
bool tryLock(Mutex& mutex)
{
@@ -1480,6 +1483,7 @@
int jpegQuality, thumbQuality;
Size thumbSize;
+ bool outputThumbnail = true;
if (req->setting.exists(ANDROID_JPEG_QUALITY)) {
camera_metadata_entry entry =
@@ -1505,6 +1509,9 @@
thumbSize = Size { static_cast<uint32_t>(entry.data.i32[0]),
static_cast<uint32_t>(entry.data.i32[1])
};
+ if (thumbSize.width == 0 && thumbSize.height == 0) {
+ outputThumbnail = false;
+ }
} else {
return lfail(
"%s: ANDROID_JPEG_THUMBNAIL_SIZE not set", __FUNCTION__);
@@ -1532,14 +1539,16 @@
/* Hold actual thumbnail and main image code sizes */
size_t thumbCodeSize = 0, jpegCodeSize = 0;
/* Temporary thumbnail code buffer */
- std::vector<uint8_t> thumbCode(maxThumbCodeSize);
+ std::vector<uint8_t> thumbCode(outputThumbnail ? maxThumbCodeSize : 0);
YCbCrLayout yu12Thumb;
- ret = cropAndScaleThumbLocked(mYu12Frame, thumbSize, &yu12Thumb);
+ if (outputThumbnail) {
+ ret = cropAndScaleThumbLocked(mYu12Frame, thumbSize, &yu12Thumb);
- if (ret != 0) {
- return lfail(
- "%s: crop and scale thumbnail failed!", __FUNCTION__);
+ if (ret != 0) {
+ return lfail(
+ "%s: crop and scale thumbnail failed!", __FUNCTION__);
+ }
}
/* Scale and crop main jpeg */
@@ -1550,12 +1559,14 @@
}
/* Encode the thumbnail image */
- ret = encodeJpegYU12(thumbSize, yu12Thumb,
- thumbQuality, 0, 0,
- &thumbCode[0], maxThumbCodeSize, thumbCodeSize);
+ if (outputThumbnail) {
+ ret = encodeJpegYU12(thumbSize, yu12Thumb,
+ thumbQuality, 0, 0,
+ &thumbCode[0], maxThumbCodeSize, thumbCodeSize);
- if (ret != 0) {
- return lfail("%s: encodeJpegYU12 failed with %d",__FUNCTION__, ret);
+ if (ret != 0) {
+ return lfail("%s: thumbnail encodeJpegYU12 failed with %d",__FUNCTION__, ret);
+ }
}
/* Combine camera characteristics with request settings to form EXIF
@@ -1570,11 +1581,7 @@
utils->setFromMetadata(meta, jpegSize.width, jpegSize.height);
- /* Check if we made a non-zero-sized thumbnail. Currently not possible
- * that we got this far and the code is size 0, but if this code moves
- * around it might become relevant again */
-
- ret = utils->generateApp1(thumbCodeSize ? &thumbCode[0] : 0, thumbCodeSize);
+ ret = utils->generateApp1(outputThumbnail ? &thumbCode[0] : 0, thumbCodeSize);
if (!ret) {
return lfail("%s: generating APP1 failed", __FUNCTION__);
@@ -2109,8 +2116,20 @@
fmt.fmt.pix.pixelformat = v4l2Fmt.fourcc;
ret = TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_S_FMT, &fmt));
if (ret < 0) {
- ALOGE("%s: S_FMT ioctl failed: %s", __FUNCTION__, strerror(errno));
- return -errno;
+ int numAttempt = 0;
+ while (ret < 0) {
+ ALOGW("%s: VIDIOC_S_FMT failed, wait 33ms and try again", __FUNCTION__);
+ usleep(IOCTL_RETRY_SLEEP_US); // sleep 100 ms and try again
+ ret = TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_S_FMT, &fmt));
+ if (numAttempt == MAX_RETRY) {
+ break;
+ }
+ numAttempt++;
+ }
+ if (ret < 0) {
+ ALOGE("%s: S_FMT ioctl failed: %s", __FUNCTION__, strerror(errno));
+ return -errno;
+ }
}
if (v4l2Fmt.width != fmt.fmt.pix.width || v4l2Fmt.height != fmt.fmt.pix.height ||
@@ -2199,9 +2218,22 @@
// VIDIOC_STREAMON: start streaming
v4l2_buf_type capture_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_STREAMON, &capture_type)) < 0) {
- ALOGE("%s: VIDIOC_STREAMON failed: %s", __FUNCTION__, strerror(errno));
- return -errno;
+ ret = TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_STREAMON, &capture_type));
+ if (ret < 0) {
+ int numAttempt = 0;
+ while (ret < 0) {
+ ALOGW("%s: VIDIOC_STREAMON failed, wait 33ms and try again", __FUNCTION__);
+ usleep(IOCTL_RETRY_SLEEP_US); // sleep 100 ms and try again
+ ret = TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_STREAMON, &capture_type));
+ if (numAttempt == MAX_RETRY) {
+ break;
+ }
+ numAttempt++;
+ }
+ if (ret < 0) {
+ ALOGE("%s: VIDIOC_STREAMON ioctl failed: %s", __FUNCTION__, strerror(errno));
+ return -errno;
+ }
}
// Swallow first few frames after streamOn to account for bad frames from some devices
@@ -2220,6 +2252,8 @@
}
}
+ ALOGI("%s: start V4L2 streaming %dx%d@%ffps",
+ __FUNCTION__, v4l2Fmt.width, v4l2Fmt.height, fps);
mV4l2StreamingFmt = v4l2Fmt;
mV4l2Streaming = true;
return OK;
@@ -2388,6 +2422,7 @@
uint32_t maxDim = 0;
for (const auto& stream : config.streams) {
float aspectRatio = ASPECT_RATIO(stream);
+ ALOGI("%s: request stream %dx%d", __FUNCTION__, stream.width, stream.height);
if ((mCroppingType == VERTICAL && aspectRatio < desiredAr) ||
(mCroppingType == HORIZONTAL && aspectRatio > desiredAr)) {
desiredAr = aspectRatio;
@@ -2572,6 +2607,9 @@
const uint8_t nrMode = ANDROID_NOISE_REDUCTION_MODE_OFF;
UPDATE(md, ANDROID_NOISE_REDUCTION_MODE, &nrMode, 1);
+ const int32_t testPatternModes = ANDROID_SENSOR_TEST_PATTERN_MODE_OFF;
+ UPDATE(md, ANDROID_SENSOR_TEST_PATTERN_MODE, &testPatternModes, 1);
+
const uint8_t fdMode = ANDROID_STATISTICS_FACE_DETECT_MODE_OFF;
UPDATE(md, ANDROID_STATISTICS_FACE_DETECT_MODE, &fdMode, 1);
@@ -2596,7 +2634,7 @@
}
}
int32_t defaultFramerate = support30Fps ? 30 : maxFps;
- int32_t defaultFpsRange[] = {defaultFramerate, defaultFramerate};
+ int32_t defaultFpsRange[] = {defaultFramerate / 2, defaultFramerate};
UPDATE(md, ANDROID_CONTROL_AE_TARGET_FPS_RANGE, defaultFpsRange, ARRAY_SIZE(defaultFpsRange));
uint8_t antibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_MODE_AUTO;
@@ -2691,6 +2729,10 @@
const uint8_t flashState = ANDROID_FLASH_STATE_UNAVAILABLE;
UPDATE(md, ANDROID_FLASH_STATE, &flashState, 1);
+ // This means pipeline latency of X frame intervals. The maximum number is 4.
+ const uint8_t requestPipelineMaxDepth = 4;
+ UPDATE(md, ANDROID_REQUEST_PIPELINE_DEPTH, &requestPipelineMaxDepth, 1);
+
// android.scaler
const int32_t crop_region[] = {
active_array_size.data.i32[0], active_array_size.data.i32[1],
diff --git a/camera/device/3.4/default/ExternalCameraUtils.cpp b/camera/device/3.4/default/ExternalCameraUtils.cpp
index d28a4dd..2e2f73b 100644
--- a/camera/device/3.4/default/ExternalCameraUtils.cpp
+++ b/camera/device/3.4/default/ExternalCameraUtils.cpp
@@ -283,9 +283,8 @@
numVideoBuffers(kDefaultNumVideoBuffer),
numStillBuffers(kDefaultNumStillBuffer) {
fpsLimits.push_back({/*Size*/{ 640, 480}, /*FPS upper bound*/30.0});
- fpsLimits.push_back({/*Size*/{1280, 720}, /*FPS upper bound*/15.0});
- fpsLimits.push_back({/*Size*/{1920, 1080}, /*FPS upper bound*/10.0});
- fpsLimits.push_back({/*Size*/{4096, 3072}, /*FPS upper bound*/5.0});
+ fpsLimits.push_back({/*Size*/{1280, 720}, /*FPS upper bound*/7.5});
+ fpsLimits.push_back({/*Size*/{1920, 1080}, /*FPS upper bound*/5.0});
}
diff --git a/camera/provider/2.4/ICameraProvider.hal b/camera/provider/2.4/ICameraProvider.hal
index abb6366..8773bc0 100644
--- a/camera/provider/2.4/ICameraProvider.hal
+++ b/camera/provider/2.4/ICameraProvider.hal
@@ -35,7 +35,8 @@
* where
* - <major>/<minor> is the provider HAL HIDL version,
* - <type> is the type of devices this provider knows about, such as
- * "internal", "legacy", "external", or "remote"
+ * "internal", "legacy", "external", "remote" etc. The camera framework
+ * must not differentiate or chage its behavior based on the specific type.
* - <instance> is a non-negative integer starting from 0 to disambiguate
* between multiple HALs of the same type.
*
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index dd8d92d..370ffdd 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -182,7 +182,14 @@
<interface>
<name>IKeymasterDevice</name>
<instance>default</instance>
- <!-- TODO: strongbox here? -->
+ </interface>
+ </hal>
+ <hal format="hidl" optional="true">
+ <name>android.hardware.keymaster</name>
+ <version>4.0</version>
+ <interface>
+ <name>IKeymasterDevice</name>
+ <instance>strongbox</instance>
</interface>
</hal>
<hal format="hidl" optional="true">
@@ -214,6 +221,15 @@
</interface>
</hal>
<hal format="hidl" optional="true">
+ <name>android.hardware.neuralnetworks</name>
+ <version>1.0</version>
+ <interface>
+ <name>IDevice</name>
+ <!-- TODO(b/73738616): This should be * (match any) -->
+ <instance>hvx</instance>
+ </interface>
+ </hal>
+ <hal format="hidl" optional="true">
<name>android.hardware.nfc</name>
<version>1.0</version>
<interface>
@@ -275,7 +291,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.soundtrigger</name>
- <version>2.0</version>
+ <version>2.0-1</version>
<interface>
<name>ISoundTriggerHw</name>
<instance>default</instance>
@@ -330,8 +346,16 @@
</interface>
</hal>
<hal format="hidl" optional="true">
+ <name>android.hardware.usb.gadget</name>
+ <version>1.0</version>
+ <interface>
+ <name>IUsbGadget</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+ <hal format="hidl" optional="true">
<name>android.hardware.vibrator</name>
- <version>1.0-1</version>
+ <version>1.0-2</version>
<interface>
<name>IVibrator</name>
<instance>default</instance>
@@ -355,13 +379,21 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.wifi</name>
- <version>1.0-1</version>
+ <version>1.0-2</version>
<interface>
<name>IWifi</name>
<instance>default</instance>
</interface>
</hal>
<hal format="hidl" optional="true">
+ <name>android.hardware.wifi.hostapd</name>
+ <version>1.0</version>
+ <interface>
+ <name>IHostapd</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+ <hal format="hidl" optional="true">
<name>android.hardware.wifi.offload</name>
<version>1.0</version>
<interface>
@@ -371,7 +403,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.wifi.supplicant</name>
- <version>1.0</version>
+ <version>1.0-1</version>
<interface>
<name>ISupplicant</name>
<instance>default</instance>
diff --git a/confirmationui/support/include/android/hardware/confirmationui/support/msg_formatting.h b/confirmationui/support/include/android/hardware/confirmationui/support/msg_formatting.h
index 0d03591..6558799 100644
--- a/confirmationui/support/include/android/hardware/confirmationui/support/msg_formatting.h
+++ b/confirmationui/support/include/android/hardware/confirmationui/support/msg_formatting.h
@@ -105,6 +105,7 @@
PromptUserConfirmation,
DeliverSecureInputEvent,
Abort,
+ Vendor,
};
template <Command cmd>
@@ -115,6 +116,7 @@
DECLARE_COMMAND(PromptUserConfirmation);
DECLARE_COMMAND(DeliverSecureInputEvent);
DECLARE_COMMAND(Abort);
+DECLARE_COMMAND(Vendor);
using PromptUserConfirmationMsg = Message<PromptUserConfirmation_t, hidl_string, hidl_vec<uint8_t>,
hidl_string, hidl_vec<UIOption>>;
@@ -166,7 +168,7 @@
}
inline void zero(const volatile uint8_t*, const volatile uint8_t*) {}
// This odd alignment function aligns the stream position to a 4byte and never 8byte boundary
-// It is to accommodate the 4 byte size field which is then followed by 8byte alligned data.
+// It is to accommodate the 4 byte size field which is then followed by 8byte aligned data.
template <typename T>
StreamState<T> unalign(StreamState<T> s) {
uint8_t unalignment = uintptr_t(s.pos_) & 0x3;
diff --git a/current.txt b/current.txt
index 29f152f..69ad1ed 100644
--- a/current.txt
+++ b/current.txt
@@ -251,7 +251,7 @@
# ABI preserving changes to HALs during Android P
cf72ff5a52bfa4d08e9e1000cf3ab5952a2d280c7f13cdad5ab7905c08050766 android.hardware.camera.metadata@3.2::types
-7b4723305354193b889a24153e1292fec62d5a5127bdfba08a5a27440f092de9 android.hardware.camera.provider@2.4::ICameraProvider
+3902efc42097cba55f0655aa389e052ea70164e99ced1a6d1ef53dafc13f7650 android.hardware.camera.provider@2.4::ICameraProvider
6fa9804a17a8bb7923a56bd10493a5483c20007e4c9026fd04287bee7c945a8c android.hardware.gnss@1.0::IGnssCallback
fb92e2b40f8e9d494e8fd3b4ac18499a3216342e7cff160714c3bbf3660b6e79 android.hardware.gnss@1.0::IGnssConfiguration
251594ea9b27447bfa005ebd806e58fb0ae4aad84a69938129c9800ec0c64eda android.hardware.gnss@1.0::IGnssMeasurementCallback
@@ -268,7 +268,7 @@
888ac906461327fa0bd93854d5109be8c292a33afdb467164826970a8bd5b789 android.hardware.audio@4.0::IStreamOut
15f6ae78e73344c8e7d68847ef03caec64fcd9f951bbcf59957d1712c247fcff android.hardware.audio@4.0::IStreamOutCallback
e8abfc73b7f3c2095ea4fad83b5f42bced4315de2abcc3199376af880dac451b android.hardware.audio@4.0::types
-dac6018ece5af342708766287a2de2e7f3bd7e60f373dc2dddc4d4d1554e1b35 android.hardware.audio.common@4.0::types
+5d47a2ad2c136b8aba067dd45bb10d0ad390dd76340764154f580658f98f4fe6 android.hardware.audio.common@4.0::types
b04b6b364938b80008e61fa2e318bc299622433e57c2e1f6cfba332a3f6e3f15 android.hardware.audio.effect@4.0::IAcousticEchoCancelerEffect
1c17d4ece5c8ba3f7a646a305ee0dd109b0d51372e1bd585812e513cd40e1852 android.hardware.audio.effect@4.0::IAutomaticGainControlEffect
34174259fe6fbb1bb14e7103e097f2f25529271a676687845b2f55d6d0d9d617 android.hardware.audio.effect@4.0::IBassBoostEffect
@@ -294,7 +294,7 @@
3b17c1fdfc389e0abe626c37054954b07201127d890c2bc05d47613ec1f4de4f android.hardware.automotive.evs@1.0::types
b3caf524c46a47d67e6453a34419e1881942d059e146cda740502670e9a752c3 android.hardware.automotive.vehicle@2.0::IVehicle
80fb4156fa91ce86e49bd2cabe215078f6b69591d416a09e914532eae6712052 android.hardware.automotive.vehicle@2.0::IVehicleCallback
-442de3a3d3819ff8b8bfe9ec710592ca8af7c16bfdb5eb8911b898b8f12b2bb0 android.hardware.automotive.vehicle@2.0::types
+4ff0dcfb938a5df283eef47de33b4e1284fab73f584cfc0c94e97317bdb7bf26 android.hardware.automotive.vehicle@2.0::types
32cc50cc2a7658ec613c0c2dd2accbf6a05113b749852879e818b8b7b438db19 android.hardware.bluetooth.a2dp@1.0::IBluetoothAudioHost
ff4be64d7992f8bec97dff37f35450e79b3430c61f85f54322ce45bef229dc3b android.hardware.bluetooth.a2dp@1.0::IBluetoothAudioOffload
27f22d2e873e6201f9620cf4d8e2facb25bd0dd30a2b911e441b4600d560fa62 android.hardware.bluetooth.a2dp@1.0::types
@@ -316,7 +316,7 @@
fef2f0ebde7704548fb203df46673ceb342272fc4fa9d0af25a980d2584a36e7 android.hardware.drm@1.1::IDrmPlugin
5047a346ecce239404b9020959f60dd467318e9c17b290a6386bc3894df62c3c android.hardware.drm@1.1::types
be794f5df97f134d6dcabb866b250d1305100e7ae07fb253b7841df890b931bb android.hardware.gnss@1.1::IGnss
-3b912f07e276de598155615491b35f151f59cb2d7a100c831f04a23f4d625311 android.hardware.gnss@1.1::IGnssCallback
+8ad55bc35bb3a83e65c018bdfde7ae5ebc749ff2bf6b79412ded0bc6c89b97d8 android.hardware.gnss@1.1::IGnssCallback
3c5183d7506010be57e0f748e3640fc2ded1ba955784b6256ba427f4c399591c android.hardware.gnss@1.1::IGnssConfiguration
b054af24fbb70d54cde1fb5cba126809e7c4e863e8f9115dc492321dfbcbc993 android.hardware.gnss@1.1::IGnssMeasurement
83e7a10ff3702147bd7ffa04567b20d407a3b16bbb7705644af44d919afe9103 android.hardware.gnss@1.1::IGnssMeasurementCallback
diff --git a/drm/1.1/Android.bp b/drm/1.1/Android.bp
index ed8196e..dba3e42 100644
--- a/drm/1.1/Android.bp
+++ b/drm/1.1/Android.bp
@@ -17,8 +17,10 @@
"android.hidl.base@1.0",
],
types: [
+ "DrmMetricGroup",
"HdcpLevel",
"KeyRequestType",
+ "SecureStopRelease",
"SecurityLevel",
],
gen_java: false,
diff --git a/gnss/1.1/IGnssCallback.hal b/gnss/1.1/IGnssCallback.hal
index fdd2ebe..7313340 100644
--- a/gnss/1.1/IGnssCallback.hal
+++ b/gnss/1.1/IGnssCallback.hal
@@ -30,6 +30,9 @@
* This is a user-visible string that identifies the model and version of the GNSS HAL.
* For example "ABC Co., Baseband Part 1234, RF Part 567, Software version 3.14.159"
*
+ * For privacy reasons, this string must not contain any device-specific serial number or other
+ * identifier that uniquely identifies an individual device.
+ *
* This must be called in response to IGnss::setCallback
*
* @param name String providing the name of the GNSS HAL implementation
diff --git a/graphics/mapper/2.1/Android.bp b/graphics/mapper/2.1/Android.bp
index d917e59..8527d3d 100644
--- a/graphics/mapper/2.1/Android.bp
+++ b/graphics/mapper/2.1/Android.bp
@@ -11,6 +11,7 @@
"IMapper.hal",
],
interfaces: [
+ "android.hardware.graphics.common@1.0",
"android.hardware.graphics.common@1.1",
"android.hardware.graphics.mapper@2.0",
"android.hidl.base@1.0",
diff --git a/neuralnetworks/1.1/Android.bp b/neuralnetworks/1.1/Android.bp
index 9365d4e..81bcef3 100644
--- a/neuralnetworks/1.1/Android.bp
+++ b/neuralnetworks/1.1/Android.bp
@@ -15,6 +15,7 @@
"android.hidl.base@1.0",
],
types: [
+ "Capabilities",
"Model",
"Operation",
"OperationType",
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1BasicTest.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1BasicTest.cpp
index 17f6744..10591dc 100644
--- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1BasicTest.cpp
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworksV1_1BasicTest.cpp
@@ -286,6 +286,169 @@
EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, executionReturnStatus);
}
+class NeuralnetworksInputsOutputsTest
+ : public NeuralnetworksHidlTest,
+ public ::testing::WithParamInterface<std::tuple<bool, bool>> {
+ protected:
+ virtual void SetUp() { NeuralnetworksHidlTest::SetUp(); }
+ virtual void TearDown() { NeuralnetworksHidlTest::TearDown(); }
+ V1_1::Model createModel(const std::vector<uint32_t>& inputs,
+ const std::vector<uint32_t>& outputs) {
+ // We set up the operands as floating-point with no designated
+ // model inputs and outputs, and then patch type and lifetime
+ // later on in this function.
+
+ std::vector<Operand> operands = {
+ {
+ .type = OperandType::TENSOR_FLOAT32,
+ .dimensions = {1},
+ .numberOfConsumers = 1,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::TEMPORARY_VARIABLE,
+ .location = {.poolIndex = 0, .offset = 0, .length = 0},
+ },
+ {
+ .type = OperandType::TENSOR_FLOAT32,
+ .dimensions = {1},
+ .numberOfConsumers = 1,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::TEMPORARY_VARIABLE,
+ .location = {.poolIndex = 0, .offset = 0, .length = 0},
+ },
+ {
+ .type = OperandType::INT32,
+ .dimensions = {},
+ .numberOfConsumers = 1,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::CONSTANT_COPY,
+ .location = {.poolIndex = 0, .offset = 0, .length = sizeof(int32_t)},
+ },
+ {
+ .type = OperandType::TENSOR_FLOAT32,
+ .dimensions = {1},
+ .numberOfConsumers = 0,
+ .scale = 0.0f,
+ .zeroPoint = 0,
+ .lifetime = OperandLifeTime::TEMPORARY_VARIABLE,
+ .location = {.poolIndex = 0, .offset = 0, .length = 0},
+ },
+ };
+
+ const std::vector<Operation> operations = {{
+ .type = OperationType::ADD, .inputs = {0, 1, 2}, .outputs = {3},
+ }};
+
+ std::vector<uint8_t> operandValues;
+ int32_t activation[1] = {static_cast<int32_t>(FusedActivationFunc::NONE)};
+ operandValues.insert(operandValues.end(), reinterpret_cast<const uint8_t*>(&activation[0]),
+ reinterpret_cast<const uint8_t*>(&activation[1]));
+
+ if (kQuantized) {
+ for (auto& operand : operands) {
+ if (operand.type == OperandType::TENSOR_FLOAT32) {
+ operand.type = OperandType::TENSOR_QUANT8_ASYMM;
+ operand.scale = 1.0f;
+ operand.zeroPoint = 0;
+ }
+ }
+ }
+
+ auto patchLifetime = [&operands](const std::vector<uint32_t>& operandIndexes,
+ OperandLifeTime lifetime) {
+ for (uint32_t index : operandIndexes) {
+ operands[index].lifetime = lifetime;
+ }
+ };
+ if (kInputHasPrecedence) {
+ patchLifetime(outputs, OperandLifeTime::MODEL_OUTPUT);
+ patchLifetime(inputs, OperandLifeTime::MODEL_INPUT);
+ } else {
+ patchLifetime(inputs, OperandLifeTime::MODEL_INPUT);
+ patchLifetime(outputs, OperandLifeTime::MODEL_OUTPUT);
+ }
+
+ return {
+ .operands = operands,
+ .operations = operations,
+ .inputIndexes = inputs,
+ .outputIndexes = outputs,
+ .operandValues = operandValues,
+ .pools = {},
+ };
+ }
+ void check(const std::string& name,
+ bool expectation, // true = success
+ const std::vector<uint32_t>& inputs, const std::vector<uint32_t>& outputs) {
+ SCOPED_TRACE(name + " (HAL calls should " + (expectation ? "succeed" : "fail") + ", " +
+ (kInputHasPrecedence ? "input" : "output") + " precedence, " +
+ (kQuantized ? "quantized" : "float"));
+
+ V1_1::Model model = createModel(inputs, outputs);
+
+ // ensure that getSupportedOperations_1_1() checks model validity
+ ErrorStatus supportedOpsErrorStatus = ErrorStatus::GENERAL_FAILURE;
+ Return<void> supportedOpsReturn = device->getSupportedOperations_1_1(
+ model, [&model, &supportedOpsErrorStatus](ErrorStatus status,
+ const hidl_vec<bool>& supported) {
+ supportedOpsErrorStatus = status;
+ if (status == ErrorStatus::NONE) {
+ ASSERT_EQ(supported.size(), model.operations.size());
+ }
+ });
+ ASSERT_TRUE(supportedOpsReturn.isOk());
+ ASSERT_EQ(supportedOpsErrorStatus,
+ (expectation ? ErrorStatus::NONE : ErrorStatus::INVALID_ARGUMENT));
+
+ // ensure that prepareModel_1_1() checks model validity
+ sp<PreparedModelCallback> preparedModelCallback = new PreparedModelCallback;
+ ASSERT_NE(preparedModelCallback.get(), nullptr);
+ Return<ErrorStatus> prepareLaunchReturn =
+ device->prepareModel_1_1(model, preparedModelCallback);
+ ASSERT_TRUE(prepareLaunchReturn.isOk());
+ ASSERT_TRUE(prepareLaunchReturn == ErrorStatus::NONE ||
+ prepareLaunchReturn == ErrorStatus::INVALID_ARGUMENT);
+ bool preparationOk = (prepareLaunchReturn == ErrorStatus::NONE);
+ if (preparationOk) {
+ preparedModelCallback->wait();
+ preparationOk = (preparedModelCallback->getStatus() == ErrorStatus::NONE);
+ }
+
+ if (preparationOk) {
+ ASSERT_TRUE(expectation);
+ } else {
+ // Preparation can fail for reasons other than an invalid model --
+ // for example, perhaps not all operations are supported, or perhaps
+ // the device hit some kind of capacity limit.
+ bool invalid = prepareLaunchReturn == ErrorStatus::INVALID_ARGUMENT ||
+ preparedModelCallback->getStatus() == ErrorStatus::INVALID_ARGUMENT;
+ ASSERT_NE(expectation, invalid);
+ }
+ }
+
+ // Indicates whether an operand that appears in both the inputs
+ // and outputs vector should have lifetime appropriate for input
+ // rather than for output.
+ const bool kInputHasPrecedence = std::get<0>(GetParam());
+
+ // Indicates whether we should test TENSOR_QUANT8_ASYMM rather
+ // than TENSOR_FLOAT32.
+ const bool kQuantized = std::get<1>(GetParam());
+};
+
+TEST_P(NeuralnetworksInputsOutputsTest, Validate) {
+ check("Ok", true, {0, 1}, {3});
+ check("InputIsOutput", false, {0, 1}, {3, 0});
+ check("OutputIsInput", false, {0, 1, 3}, {3});
+ check("DuplicateInputs", false, {0, 1, 0}, {3});
+ check("DuplicateOutputs", false, {0, 1}, {3, 3});
+}
+
+INSTANTIATE_TEST_CASE_P(Flavor, NeuralnetworksInputsOutputsTest,
+ ::testing::Combine(::testing::Bool(), ::testing::Bool()));
+
} // namespace functional
} // namespace vts
} // namespace V1_1
diff --git a/wifi/1.2/default/android.hardware.wifi@1.0-service.rc b/wifi/1.2/default/android.hardware.wifi@1.0-service.rc
index eecb6d0..cf849d0 100644
--- a/wifi/1.2/default/android.hardware.wifi@1.0-service.rc
+++ b/wifi/1.2/default/android.hardware.wifi@1.0-service.rc
@@ -1,4 +1,5 @@
service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi@1.0-service
class hal
+ capabilities NET_ADMIN NET_RAW SYS_MODULE
user wifi
group wifi gps
diff --git a/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp b/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp
index 27c8d60..3928c9a 100644
--- a/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp
+++ b/wifi/1.2/default/tests/wifi_chip_unit_tests.cpp
@@ -146,7 +146,7 @@
} else if (type == IfaceType::STA) {
chip_->createStaIface(
[&iface_name](const WifiStatus& status,
- const sp<IWifiStaIface>& iface) {
+ const sp<V1_0::IWifiStaIface>& iface) {
if (WifiStatusCode::SUCCESS == status.code) {
ASSERT_NE(iface.get(), nullptr);
iface->getName([&iface_name](const WifiStatus& status,
diff --git a/wifi/1.2/default/wifi_legacy_hal.cpp b/wifi/1.2/default/wifi_legacy_hal.cpp
index 84af9c4..c314e64 100644
--- a/wifi/1.2/default/wifi_legacy_hal.cpp
+++ b/wifi/1.2/default/wifi_legacy_hal.cpp
@@ -492,6 +492,28 @@
getIfaceHandle(iface_name), program.data(), program.size());
}
+std::pair<wifi_error, std::vector<uint8_t>>
+WifiLegacyHal::readApfPacketFilterData(const std::string& iface_name) {
+ if (global_func_table_.wifi_read_packet_filter == nullptr) {
+ return {WIFI_ERROR_NOT_SUPPORTED, {}};
+ }
+
+ PacketFilterCapabilities caps;
+ wifi_error status = global_func_table_.wifi_get_packet_filter_capabilities(
+ getIfaceHandle(iface_name), &caps.version, &caps.max_len);
+ if (status != WIFI_SUCCESS) {
+ return {status, {}};
+ }
+
+ // Size the buffer to read the entire program & work memory.
+ std::vector<uint8_t> buffer(caps.max_len);
+
+ status = global_func_table_.wifi_read_packet_filter(
+ getIfaceHandle(iface_name), /*src_offset=*/0, buffer.data(),
+ buffer.size());
+ return {status, move(buffer)};
+}
+
std::pair<wifi_error, wifi_gscan_capabilities>
WifiLegacyHal::getGscanCapabilities(const std::string& iface_name) {
wifi_gscan_capabilities caps;
diff --git a/wifi/1.2/default/wifi_legacy_hal.h b/wifi/1.2/default/wifi_legacy_hal.h
index dedbbf8..60905ab 100644
--- a/wifi/1.2/default/wifi_legacy_hal.h
+++ b/wifi/1.2/default/wifi_legacy_hal.h
@@ -156,7 +156,7 @@
* Class that encapsulates all legacy HAL interactions.
* This class manages the lifetime of the event loop thread used by legacy HAL.
*
- * Note: aThere will only be a single instance of this class created in the Wifi
+ * Note: There will only be a single instance of this class created in the Wifi
* object and will be valid for the lifetime of the process.
*/
class WifiLegacyHal {
@@ -188,6 +188,8 @@
const std::string& iface_name);
wifi_error setPacketFilter(const std::string& iface_name,
const std::vector<uint8_t>& program);
+ std::pair<wifi_error, std::vector<uint8_t>> readApfPacketFilterData(
+ const std::string& iface_name);
// Gscan functions.
std::pair<wifi_error, wifi_gscan_capabilities> getGscanCapabilities(
const std::string& iface_name);
diff --git a/wifi/1.2/default/wifi_sta_iface.cpp b/wifi/1.2/default/wifi_sta_iface.cpp
index 6faf009..ab99daa 100644
--- a/wifi/1.2/default/wifi_sta_iface.cpp
+++ b/wifi/1.2/default/wifi_sta_iface.cpp
@@ -94,6 +94,13 @@
hidl_status_cb, cmd_id, program);
}
+Return<void> WifiStaIface::readApfPacketFilterData(
+ readApfPacketFilterData_cb hidl_status_cb) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
+ &WifiStaIface::readApfPacketFilterDataInternal,
+ hidl_status_cb);
+}
+
Return<void> WifiStaIface::getBackgroundScanCapabilities(
getBackgroundScanCapabilities_cb hidl_status_cb) {
return validateAndCall(this, WifiStatusCode::ERROR_WIFI_IFACE_INVALID,
@@ -297,6 +304,15 @@
return createWifiStatusFromLegacyError(legacy_status);
}
+std::pair<WifiStatus, std::vector<uint8_t>>
+WifiStaIface::readApfPacketFilterDataInternal() {
+ const std::pair<legacy_hal::wifi_error, std::vector<uint8_t>>
+ legacy_status_and_data =
+ legacy_hal_.lock()->readApfPacketFilterData(ifname_);
+ return {createWifiStatusFromLegacyError(legacy_status_and_data.first),
+ std::move(legacy_status_and_data.second)};
+}
+
std::pair<WifiStatus, StaBackgroundScanCapabilities>
WifiStaIface::getBackgroundScanCapabilitiesInternal() {
legacy_hal::wifi_error legacy_status;
diff --git a/wifi/1.2/default/wifi_sta_iface.h b/wifi/1.2/default/wifi_sta_iface.h
index 423365c..a212888 100644
--- a/wifi/1.2/default/wifi_sta_iface.h
+++ b/wifi/1.2/default/wifi_sta_iface.h
@@ -18,8 +18,8 @@
#define WIFI_STA_IFACE_H_
#include <android-base/macros.h>
-#include <android/hardware/wifi/1.0/IWifiStaIface.h>
#include <android/hardware/wifi/1.0/IWifiStaIfaceEventCallback.h>
+#include <android/hardware/wifi/1.2/IWifiStaIface.h>
#include "hidl_callback_util.h"
#include "wifi_legacy_hal.h"
@@ -34,7 +34,7 @@
/**
* HIDL interface object used to control a STA Iface instance.
*/
-class WifiStaIface : public V1_0::IWifiStaIface {
+class WifiStaIface : public V1_2::IWifiStaIface {
public:
WifiStaIface(const std::string& ifname,
const std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal);
@@ -56,6 +56,8 @@
Return<void> installApfPacketFilter(
uint32_t cmd_id, const hidl_vec<uint8_t>& program,
installApfPacketFilter_cb hidl_status_cb) override;
+ Return<void> readApfPacketFilterData(
+ readApfPacketFilterData_cb hidl_status_cb) override;
Return<void> getBackgroundScanCapabilities(
getBackgroundScanCapabilities_cb hidl_status_cb) override;
Return<void> getValidFrequenciesForBand(
@@ -113,6 +115,8 @@
getApfPacketFilterCapabilitiesInternal();
WifiStatus installApfPacketFilterInternal(
uint32_t cmd_id, const std::vector<uint8_t>& program);
+ std::pair<WifiStatus, std::vector<uint8_t>>
+ readApfPacketFilterDataInternal();
std::pair<WifiStatus, StaBackgroundScanCapabilities>
getBackgroundScanCapabilitiesInternal();
std::pair<WifiStatus, std::vector<WifiChannelInMhz>>