Merge "Add VTS tests for audio effects"
diff --git a/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp b/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
index a339f99..e50b912 100644
--- a/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
+++ b/audio/2.0/vts/functional/AudioPrimaryHidlHalTest.cpp
@@ -49,6 +49,7 @@
using ::android::hardware::hidl_handle;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
+using ::android::hardware::MQDescriptorSync;
using ::android::hardware::audio::V2_0::DeviceAddress;
using ::android::hardware::audio::V2_0::IDevice;
using ::android::hardware::audio::V2_0::IPrimaryDevice;
@@ -56,7 +57,11 @@
using ::android::hardware::audio::V2_0::IDevicesFactory;
using ::android::hardware::audio::V2_0::IStream;
using ::android::hardware::audio::V2_0::IStreamIn;
+using ReadParameters = ::android::hardware::audio::V2_0::IStreamIn::ReadParameters;
+using ReadStatus = ::android::hardware::audio::V2_0::IStreamIn::ReadStatus;
using ::android::hardware::audio::V2_0::IStreamOut;
+using ::android::hardware::audio::V2_0::MmapBufferInfo;
+using ::android::hardware::audio::V2_0::MmapPosition;
using ::android::hardware::audio::V2_0::ParameterValue;
using ::android::hardware::audio::V2_0::Result;
using ::android::hardware::audio::common::V2_0::AudioChannelMask;
@@ -70,6 +75,7 @@
using ::android::hardware::audio::common::V2_0::AudioOffloadInfo;
using ::android::hardware::audio::common::V2_0::AudioOutputFlag;
using ::android::hardware::audio::common::V2_0::AudioSource;
+using ::android::hardware::audio::common::V2_0::ThreadInfo;
using utility::returnIn;
@@ -186,60 +192,7 @@
}
//////////////////////////////////////////////////////////////////////////////
-//////////////////////////// {set,get}MasterVolume ///////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-class MasterVolumeTest : public AudioPrimaryHidlTest {
-protected:
- void testSetGetConsistency(float volume, Result expectedSetResult, float expectedGetVolume) {
- SCOPED_TRACE("Test set/get consistency for " + to_string(volume));
- auto ret = device->setMasterVolume(volume);
- ASSERT_TRUE(ret.isOk());
- ASSERT_EQ(expectedSetResult, ret);
-
- float observedVolume;
- ASSERT_OK(device->getMasterVolume(returnIn(res, observedVolume)));
- ASSERT_OK(res);
-
- // Check that `get` returned the expected value
- EXPECT_EQ(expectedGetVolume, observedVolume);
- }
-};
-
-TEST_F(MasterVolumeTest, MasterVolumeTest) {
- doc::test("Test the master volume if supported");
- {
- SCOPED_TRACE("Check for master volume support");
- auto ret = device->setMasterVolume(1);
- ASSERT_TRUE(ret.isOk());
- if (ret == Result::NOT_SUPPORTED) {
- doc::partialTest("Master volume is not supported");
- return;
- }
- }
- // NOTE: this code has never been tested on a platform supporting MasterVolume
- float lastValidVolumeSet;
- using Volumes = float[];
- SCOPED_TRACE("As set/get master volume are supported...");
- {
- SCOPED_TRACE("...test them with valid values");
- for (float validVolume : Volumes{0, 0.5, 1}) {
- ASSERT_NO_FATAL_FAILURE(testSetGetConsistency(validVolume, Result::OK, validVolume));
- lastValidVolumeSet = validVolume;
- }
- }{
- SCOPED_TRACE("...test them with tricky values");
- for (float outOfBoundVolume :Volumes{-0.1, 1.1, NAN, INFINITY, -INFINITY,
- 1 + std::numeric_limits<float>::epsilon()}) {
- ASSERT_NO_FATAL_FAILURE(testSetGetConsistency(outOfBoundVolume,
- Result::INVALID_ARGUMENTS,
- lastValidVolumeSet));
- }
- }
-}
-
-//////////////////////////////////////////////////////////////////////////////
-////////////////////////// {set,get}{Master,Mic}Mute /////////////////////////
+///////////////////// {set,get}{Master,Mic}{Mute,Volume} /////////////////////
//////////////////////////////////////////////////////////////////////////////
template <class Property>
@@ -249,14 +202,16 @@
/** Test a property getter and setter. */
template <class Getter, class Setter>
void testAccessors(const string& propertyName, const vector<Property>& valuesToTest,
- Setter setter, Getter getter) {
+ 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));
+ 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
@@ -265,13 +220,20 @@
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) {
+ 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");
@@ -284,7 +246,7 @@
ASSERT_OK(res); // If it is supported it must succeed
}
// The feature is supported, test it
- testAccessors(propertyName, valuesToTest, setter, getter);
+ testAccessors(propertyName, valuesToTest, setter, getter, invalidValues);
}
};
@@ -303,6 +265,39 @@
// 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_TRUE(result.isOk());
+ 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
@@ -310,7 +305,7 @@
/////////// TODO: move to the beginning of the file for easier update ////////
//////////////////////////////////////////////////////////////////////////////
-class AudioConfigPrimaryTest : public AudioPrimaryHidlTest {
+class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest {
public:
// Cache result ?
static const vector<AudioConfig> getRequiredSupportPlaybackAudioConfig() {
@@ -369,6 +364,20 @@
}
};
+/** 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 == AudioChannelMask::OUT_MONO ||
+ config.channelMask == AudioChannelMask::IN_MONO) ?
+ "MONO" : toString(config.channelMask));
+}
+
//////////////////////////////////////////////////////////////////////////////
///////////////////////////// getInputBufferSize /////////////////////////////
//////////////////////////////////////////////////////////////////////////////
@@ -406,10 +415,12 @@
}
INSTANTIATE_TEST_CASE_P(
RequiredInputBufferSize, RequiredInputBufferSizeTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()));
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
+ &generateTestName);
INSTANTIATE_TEST_CASE_P(
SupportedInputBufferSize, RequiredInputBufferSizeTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()));
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
+ &generateTestName);
// Test that the recommended capture config are supported or lead to a INVALID_ARGUMENTS return
class OptionalInputBufferSizeTest : public AudioCaptureConfigPrimaryTest {};
@@ -419,7 +430,8 @@
}
INSTANTIATE_TEST_CASE_P(
RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()));
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
+ &generateTestName);
//////////////////////////////////////////////////////////////////////////////
/////////////////////////////// setScreenState ///////////////////////////////
@@ -453,8 +465,8 @@
//////////////////////////////// debugDebug //////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
-TEST_F(AudioPrimaryHidlTest, debugDump) {
- doc::test("Check that the hal can dump its state without error");
+template <class DebugDump>
+static void testDebugDump(DebugDump debugDump) {
FILE* file = tmpfile();
ASSERT_NE(nullptr, file) << errno;
@@ -465,28 +477,23 @@
hidl_handle handle;
handle.setTo(nativeHandle, true /*take ownership*/);
- auto ret = device->debugDump(handle);
- ASSERT_TRUE(ret.isOk());
-
- // FIXME: debugDump does not return a Result.
+ // TODO: debugDump does not return a Result.
// This mean that the hal can not report that it not implementing the function.
- // As the default hal does not implement debugDump, the function can not be tested.
- /*
- res = ret;
- if (res == Result::NOT_SUPPORTED) {
- doc::partialTest("debugDump is not implemented");
- return;
- }
- ASSERT_OK(res);
- rewind(file);
+ ASSERT_OK(debugDump(handle));
+
+ rewind(file); // can not fail
// Check that at least one bit was written by the hal
char buff;
- ASSERT_EQ(1, fread(&buff, sizeof(buff), 1, file));
- */
+ ASSERT_EQ(size_t{1}, fread(&buff, sizeof(buff), 1, file));
EXPECT_EQ(0, fclose(file)) << errno;
}
+TEST_F(AudioPrimaryHidlTest, debugDump) {
+ doc::test("Check that the hal can dump its state without error");
+ testDebugDump([this](const auto& handle){ return device->debugDump(handle); });
+}
+
//////////////////////////////////////////////////////////////////////////////
////////////////////////// open{Output,Input}Stream //////////////////////////
//////////////////////////////////////////////////////////////////////////////
@@ -526,6 +533,10 @@
open = true;
}
+ Return<Result> closeStream() {
+ open = false;
+ return stream->close();
+ }
private:
void TearDown() override {
if (open) {
@@ -536,6 +547,7 @@
protected:
AudioConfig audioConfig;
+ DeviceAddress address = {};
sp<Stream> stream;
bool open = false;
};
@@ -545,12 +557,11 @@
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();
- DeviceAddress deviceAddr{}; // Ignored by primary hal
AudioOutputFlag flags = AudioOutputFlag::NONE; // TODO: test all flag combination
testOpen([&](AudioIoHandle handle, AudioConfig config, auto cb)
- { return device->openOutputStream(handle, deviceAddr, config, flags, cb); },
+ { return device->openOutputStream(handle, address, config, flags, cb); },
config);
}
};
@@ -560,14 +571,17 @@
}
INSTANTIATE_TEST_CASE_P(
RequiredOutputStreamConfigSupport, OutputStreamTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportPlaybackAudioConfig()));
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportPlaybackAudioConfig()),
+ &generateTestName);
INSTANTIATE_TEST_CASE_P(
SupportedOutputStreamConfig, OutputStreamTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedPlaybackAudioConfig()));
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedPlaybackAudioConfig()),
+ &generateTestName);
INSTANTIATE_TEST_CASE_P(
RecommendedOutputStreamConfigSupport, OutputStreamTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportPlaybackAudioConfig()));
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportPlaybackAudioConfig()),
+ &generateTestName);
////////////////////////////// openInputStream //////////////////////////////
@@ -575,13 +589,12 @@
virtual void SetUp() override {
ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base
-
+ address.device = AudioDevice::IN_DEFAULT;
const AudioConfig& config = GetParam();
- DeviceAddress deviceAddr{}; // TODO: test all devices
AudioInputFlag flags = AudioInputFlag::NONE; // TODO: test all flag combination
AudioSource source = AudioSource::DEFAULT; // TODO: test all flag combination
testOpen([&](AudioIoHandle handle, AudioConfig config, auto cb)
- { return device->openInputStream(handle, deviceAddr, config, flags, source, cb); },
+ { return device->openInputStream(handle, address, config, flags, source, cb); },
config);
}
};
@@ -592,14 +605,17 @@
}
INSTANTIATE_TEST_CASE_P(
RequiredInputStreamConfigSupport, InputStreamTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()));
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
+ &generateTestName);
INSTANTIATE_TEST_CASE_P(
SupportedInputStreamConfig, InputStreamTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()));
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
+ &generateTestName);
INSTANTIATE_TEST_CASE_P(
RecommendedInputStreamConfigSupport, InputStreamTest,
- ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()));
+ ::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
+ &generateTestName);
//////////////////////////////////////////////////////////////////////////////
////////////////////////////// IStream getters ///////////////////////////////
@@ -616,8 +632,40 @@
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 CapabilityGetter, class Getter, class Setter>
-static void testCapabilityGetter(const string& name,IStream* stream, Property currentValue,
+static void testCapabilityGetter(const string& name, IStream* stream, Property currentValue,
CapabilityGetter capablityGetter, Getter getter, Setter setter) {
hidl_vec<Property> capabilities;
ASSERT_OK((stream->*capablityGetter)(returnIn(capabilities)));
@@ -640,6 +688,48 @@
}
}
+TEST_IO_STREAM(SupportedSampleRate, "Check that the stream sample rate is declared as supported",
+ testCapabilityGetter("getSupportedSampleRate", stream.get(), \
+ extract(stream->getSampleRate()), \
+ &IStream::getSupportedSampleRates, \
+ &IStream::getSampleRate, &IStream::setSampleRate))
+
+TEST_IO_STREAM(SupportedChannelMask, "Check that the stream channel mask is declared as supported",
+ testCapabilityGetter("getSupportedChannelMask", stream.get(), \
+ extract(stream->getChannelMask()), \
+ &IStream::getSupportedChannelMasks, \
+ &IStream::getChannelMask, &IStream::setChannelMask))
+
+TEST_IO_STREAM(SupportedFormat, "Check that the stream format is declared as supported",
+ testCapabilityGetter("getSupportedFormat", stream.get(), \
+ extract(stream->getFormat()), \
+ &IStream::getSupportedFormats, \
+ &IStream::getFormat, &IStream::setFormat))
+
+static void testGetDevice(IStream* stream, AudioDevice expectedDevice) {
+ auto ret = stream->getDevice();
+ ASSERT_TRUE(ret.isOk());
+ AudioDevice device = ret;
+ ASSERT_EQ(expectedDevice, 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->setDevice(otherAddress));
+
+ ASSERT_OK(stream->setDevice(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;
AudioChannelMask mask;
@@ -653,90 +743,191 @@
EXPECT_EQ(expectedConfig.format, format);
}
-static void testAccessors(IStream* stream, AudioConfig audioConfig) {
- doc::test("Test IStream getters and setters that can be called in the stop state");
+TEST_IO_STREAM(GetAudioProperties,
+ "Check that the stream audio properties == the ones it was opened with",
+ testGetAudioProperties(stream.get(), audioConfig))
- auto frameCount = extract(stream->getFrameCount());
- ASSERT_EQ(audioConfig.frameCount, frameCount);
+static void testConnectedState(IStream* stream) {
+ DeviceAddress address = {};
+ using AD = AudioDevice;
+ for (auto device : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) {
+ address.device = device;
- auto sampleRate = extract(stream->getSampleRate());
- // FIXME: the qcom hal it does not currently negotiate the sampleRate
- ASSERT_EQ(audioConfig.sampleRateHz, sampleRate);
-
- auto channelMask = extract(stream->getChannelMask());
- // FIXME: the qcom hal it does not currently negotiate the channelMask
- ASSERT_EQ(audioConfig.channelMask, channelMask);
-
- auto frameSize = extract(stream->getFrameSize());
- ASSERT_GE(frameSize, 0U);
-
- auto bufferSize = extract(stream->getBufferSize());
- ASSERT_GE(bufferSize, frameSize);
-
- testCapabilityGetter("getSupportedsampleRate", stream, sampleRate,
- &IStream::getSupportedSampleRates,
- &IStream::getSampleRate, &IStream::setSampleRate);
-
- testCapabilityGetter("getSupportedChannelMask", stream, channelMask,
- &IStream::getSupportedChannelMasks,
- &IStream::getChannelMask, &IStream::setChannelMask);
-
- AudioFormat format = extract(stream->getFormat());
- ASSERT_EQ(audioConfig.format, format);
-
- testCapabilityGetter("getSupportedFormats", stream, format,
- &IStream::getSupportedFormats, &IStream::getFormat, &IStream::setFormat);
-
- testGetAudioProperties(stream, audioConfig);
-
- auto ret = stream->getDevice();
- ASSERT_TRUE(ret.isOk());
- AudioDevice device = ret;
- ASSERT_EQ(AudioDevice::OUT_DEFAULT, device);
-}
-
-TEST_P(InputStreamTest, GettersTest) {
- testAccessors(stream.get(), audioConfig);
-}
-TEST_P(OutputStreamTest, GettersTest) {
- testAccessors(stream.get(), audioConfig);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-//////////////////////////////// AudioPatches ////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-
-TEST_F(AudioPrimaryHidlTest, AudioPatches) {
- doc::test("Test if audio patches are supported");
- auto result = device->supportsAudioPatches();
- ASSERT_TRUE(result.isOk());
- bool supportsAudioPatch = result;
- if (!supportsAudioPatch) {
- doc::partialTest("Audio patches are not supported");
- return;
+ ASSERT_OK(stream->setConnectedState(address, true));
+ ASSERT_OK(stream->setConnectedState(address, false));
}
- // TODO: test audio patches
+}
+TEST_IO_STREAM(SetConnectedState,
+ "Check that the stream can be notified of device connection and deconnection",
+ testConnectedState(stream.get()))
+
+
+static auto invalidArgsOrNotSupported = {Result::INVALID_ARGUMENTS, Result::NOT_SUPPORTED};
+TEST_IO_STREAM(SetHwAvSync, "Try to set hardware sync to an invalid value",
+ ASSERT_RESULT(invalidArgsOrNotSupported, stream->setHwAvSync(666)))
+
+static void checkGetParameter(IStream* stream, hidl_vec<hidl_string> keys,
+ vector<Result> expectedResults) {
+ hidl_vec<ParameterValue> parameters;
+ Result res;
+ ASSERT_OK(stream->getParameters(keys, returnIn(res, parameters)));
+ ASSERT_RESULT(expectedResults, res);
+ if (res == Result::OK) {
+ ASSERT_EQ(0U, parameters.size());
+ }
+}
+
+/* Get/Set parameter is intended to be an opaque channel between vendors app and their HALs.
+ * Thus can not be meaningfully tested.
+ * TODO: Doc missing. Should asking for an empty set of params raise an error ?
+ */
+TEST_IO_STREAM(getEmptySetParameter, "Retrieve the values of an empty set",
+ checkGetParameter(stream.get(), {} /* keys */,
+ {Result::OK, Result::INVALID_ARGUMENTS}))
+
+
+TEST_IO_STREAM(getNonExistingParameter, "Retrieve the values of an non existing parameter",
+ checkGetParameter(stream.get(), {"Non existing key"} /* keys */,
+ {Result::INVALID_ARGUMENTS}))
+
+static vector<Result> okOrNotSupported = {Result::OK, Result::INVALID_ARGUMENTS};
+TEST_IO_STREAM(setEmptySetParameter, "Set the values of an empty set of parameters",
+ ASSERT_RESULT(okOrNotSupported, stream->setParameters({})))
+
+TEST_IO_STREAM(setNonExistingParameter, "Set the values of an non existing parameter",
+ ASSERT_RESULT(Result::INVALID_ARGUMENTS,
+ 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->debugDump(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 vector<Result> 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 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)));
+ ASSERT_OK(res);
+ ASSERT_EQ(AudioSource::DEFAULT, source);
+}
+
+static void testUnitaryGain(std::function<Return<Result> (float)> setGain) {
+ for (float value : {0.0, 0.01, 0.5, 0.09, 1.0}) {
+ SCOPED_TRACE("value=" + to_string(value));
+ ASSERT_OK(setGain(value));
+ }
+ for (float value : (float[]){-INFINITY,-1.0, -0.0,
+ 1.0 + std::numeric_limits<float>::epsilon(), 2.0, INFINITY,
+ NAN}) {
+ SCOPED_TRACE("value=" + to_string(value));
+ // FIXME: NAN should never be accepted
+ // FIXME: Missing api doc. What should the impl do if the volume is outside [0,1] ?
+ ASSERT_RESULT(Result::INVALID_ARGUMENTS, setGain(value));
+ }
+}
+
+TEST_P(InputStreamTest, SetGain) {
+ doc::test("The gain of an input stream should only be set between [0,1]");
+ testUnitaryGain([this](float volume) { return stream->setGain(volume); });
+}
+
+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(invalidArgsOrNotSupported, res);
+}
+
+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, 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);
}
//////////////////////////////////////////////////////////////////////////////
/////////////////////////////// PrimaryDevice ////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
+
TEST_F(AudioPrimaryHidlTest, setVoiceVolume) {
doc::test("Make sure setVoiceVolume only succeed if volume is in [0,1]");
- for (float volume : {0.0, 0.01, 0.5, 0.09, 1.0}) {
- SCOPED_TRACE("volume=" + to_string(volume));
- ASSERT_OK(device->setVoiceVolume(volume));
- }
- for (float volume : (float[]){-INFINITY,-1.0, -0.0,
- 1.0 + std::numeric_limits<float>::epsilon(), 2.0, INFINITY,
- NAN}) {
- SCOPED_TRACE("volume=" + to_string(volume));
- // FIXME: NAN should never be accepted
- // FIXME: Missing api doc. What should the impl do if the volume is outside [0,1] ?
- ASSERT_INVALID_ARGUMENTS(device->setVoiceVolume(volume));
- }
+ testUnitaryGain([this](float volume) { return device->setVoiceVolume(volume); });
}
TEST_F(AudioPrimaryHidlTest, setMode) {
@@ -749,7 +940,7 @@
}
// FIXME: Missing api doc. What should the impl do if the mode is invalid ?
- ASSERT_INVALID_ARGUMENTS(device->setMode(AudioMode::INVALID));
+ ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(AudioMode::INVALID));
}
diff --git a/audio/2.0/vts/functional/utility/AssertOk.h b/audio/2.0/vts/functional/utility/AssertOk.h
index 16488ae..39c9a1d 100644
--- a/audio/2.0/vts/functional/utility/AssertOk.h
+++ b/audio/2.0/vts/functional/utility/AssertOk.h
@@ -13,38 +13,59 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
+#include <vector>
+#include <algorithm>
+
#include <hidl/Status.h>
namespace detail {
-inline void assertOk(::android::hardware::Return<void> ret) {
+// This is a detail namespace, thus it is OK to import a class as nobody else is allowed to use it
+using ::android::hardware::Return;
+using ::android::hardware::audio::V2_0::Result;
+
+inline void assertResult(Result expected, Result result) {
+ ASSERT_EQ(expected, result);
+}
+
+inline void assertResult(Result expected, Return<Result> ret) {
+ ASSERT_TRUE(ret.isOk());
+ Result result = ret;
+ assertResult(expected, result);
+}
+
+inline void assertResult(std::vector<Result> expected, Result result) {
+ if (std::find(expected.begin(), expected.end(), result) != expected.end()) {
+ return; // result is in expected
+ }
+ FAIL() << "Expected result " << ::testing::PrintToString(result)
+ << " to be one of " << ::testing::PrintToString(expected);
+}
+
+inline void assertResult(std::vector<Result> expected, Return<Result> ret) {
+ ASSERT_TRUE(ret.isOk());
+ Result result = ret;
+ assertResult(expected, result);
+}
+
+inline void assertOk(Return<void> ret) {
ASSERT_TRUE(ret.isOk());
}
-inline void assertOk(::android::hardware::audio::V2_0::Result result) {
- ASSERT_EQ(decltype(result)::OK, result);
+inline void assertOk(Result result) {
+ assertResult(Result::OK, result);
}
-inline void assertOk(::android::hardware::Return<::android::hardware::audio::V2_0::Result> ret) {
- ASSERT_TRUE(ret.isOk());
- ::android::hardware::audio::V2_0::Result result = ret;
- assertOk(result);
+inline void assertOk(Return<Result> ret) {
+ assertResult(Result::OK, std::move(ret));
}
-inline void assertInvalidArguments(::android::hardware::audio::V2_0::Result result) {
- ASSERT_EQ(decltype(result)::INVALID_ARGUMENTS, result);
-}
-
-inline void assertInvalidArguments(
- ::android::hardware::Return<::android::hardware::audio::V2_0::Result> ret) {
- ASSERT_TRUE(ret.isOk());
- ::android::hardware::audio::V2_0::Result result = ret;
- assertInvalidArguments(result);
-}
}
// Test anything provided is and contains only OK
#define ASSERT_OK(ret) ASSERT_NO_FATAL_FAILURE(detail::assertOk(ret))
#define EXPECT_OK(ret) EXPECT_NO_FATAL_FAILURE(detail::assertOk(ret))
-#define ASSERT_INVALID_ARGUMENTS(ret) ASSERT_NO_FATAL_FAILURE(detail::assertInvalidArguments(ret))
+#define ASSERT_RESULT(expected, ret) ASSERT_NO_FATAL_FAILURE(detail::assertResult(expected, ret))
+#define EXPECT_RESULT(expected, ret) ASSERT_NO_FATAL_FAILURE(detail::assertResult(expected, ret))
diff --git a/audio/2.0/vts/functional/utility/PrettyPrintAudioTypes.h b/audio/2.0/vts/functional/utility/PrettyPrintAudioTypes.h
index 8dfcb29..025cd1c 100644
--- a/audio/2.0/vts/functional/utility/PrettyPrintAudioTypes.h
+++ b/audio/2.0/vts/functional/utility/PrettyPrintAudioTypes.h
@@ -13,23 +13,50 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include <type_traits>
-// Use HIDL generated toString methods to pretty print gtest errors
+/** @file Use HIDL generated toString methods to pretty print gtest errors */
+
+namespace detail {
+
+// Print the value of an enum as hex
+template <class Enum>
+inline void printUnderlyingValue(Enum value, ::std::ostream* os) {
+ *os << std::hex << " (0x" << static_cast<std::underlying_type_t<Enum>>(value) << ")";
+}
+
+} // namespace detail
+
namespace android {
namespace hardware {
namespace audio {
namespace V2_0 {
+
inline void PrintTo(const Result& result, ::std::ostream* os) {
*os << toString(result);
+ detail::printUnderlyingValue(result, os);
}
+
} // namespace V2_0
namespace common {
namespace V2_0 {
+
inline void PrintTo(const AudioConfig& config, ::std::ostream* os) {
*os << toString(config);
}
+
+inline void PrintTo(const AudioDevice& device, ::std::ostream* os) {
+ *os << toString(device);
+ detail::printUnderlyingValue(device, os);
+}
+
+inline void PrintTo(const AudioChannelMask& channelMask, ::std::ostream* os) {
+ *os << toString(channelMask);
+ detail::printUnderlyingValue(channelMask, os);
+}
+
} // namespace V2_0
} // namespace common
-}
-}
-}
+} // namespace audio
+} // namespace hardware
+} // namespace android
diff --git a/camera/device/1.0/default/Android.bp b/camera/device/1.0/default/Android.bp
index eec641a..5688fc1 100644
--- a/camera/device/1.0/default/Android.bp
+++ b/camera/device/1.0/default/Android.bp
@@ -1,6 +1,7 @@
cc_library_shared {
name: "camera.device@1.0-impl",
defaults: ["hidl_defaults"],
+ proprietary: true,
srcs: [
"CameraDevice.cpp",
],
diff --git a/camera/device/3.2/default/Android.bp b/camera/device/3.2/default/Android.bp
index 3767e09..e0dc5ff 100644
--- a/camera/device/3.2/default/Android.bp
+++ b/camera/device/3.2/default/Android.bp
@@ -1,6 +1,7 @@
cc_library_shared {
name: "camera.device@3.2-impl",
defaults: ["hidl_defaults"],
+ proprietary: true,
srcs: ["CameraDevice.cpp",
"CameraDeviceSession.cpp",
"convert.cpp"],
diff --git a/configstore/1.0/ISurfaceFlingerConfigs.hal b/configstore/1.0/ISurfaceFlingerConfigs.hal
index 318590d..4c1a5a6 100644
--- a/configstore/1.0/ISurfaceFlingerConfigs.hal
+++ b/configstore/1.0/ISurfaceFlingerConfigs.hal
@@ -41,4 +41,10 @@
vsyncSfEventPhaseOffsetNs() generates (OptionalInt64 value);
useTripleFramebuffer() generates (OptionalBool value);
+
+ /*
+ * Instruct the Render Engine to use EGL_IMG_context_priority hint if
+ * availabe.
+ */
+ useContextPriority() generates(OptionalBool value);
};
diff --git a/configstore/1.0/default/SurfaceFlingerConfigs.cpp b/configstore/1.0/default/SurfaceFlingerConfigs.cpp
index f73ecb4..0aeb4f5 100644
--- a/configstore/1.0/default/SurfaceFlingerConfigs.cpp
+++ b/configstore/1.0/default/SurfaceFlingerConfigs.cpp
@@ -39,6 +39,16 @@
return Void();
}
+Return<void> SurfaceFlingerConfigs::useContextPriority(useContextPriority_cb _hidl_cb) {
+#ifdef USE_CONTEXT_PRIORITY
+ _hidl_cb({true, USE_CONTEXT_PRIORITY});
+ LOG(INFO) << "SurfaceFlinger useContextPriority=" << USE_CONTEXT_PRIORITY;
+#else
+ _hidl_cb({false, false});
+#endif
+ return Void();
+}
+
// Methods from ::android::hidl::base::V1_0::IBase follow.
ISurfaceFlingerConfigs* HIDL_FETCH_ISurfaceFlingerConfigs(const char* /* name */) {
diff --git a/configstore/1.0/default/SurfaceFlingerConfigs.h b/configstore/1.0/default/SurfaceFlingerConfigs.h
index bbb61d6..08a1b92 100644
--- a/configstore/1.0/default/SurfaceFlingerConfigs.h
+++ b/configstore/1.0/default/SurfaceFlingerConfigs.h
@@ -27,6 +27,7 @@
Return<void> vsyncEventPhaseOffsetNs(vsyncEventPhaseOffsetNs_cb _hidl_cb) override;
Return<void> vsyncSfEventPhaseOffsetNs(vsyncEventPhaseOffsetNs_cb _hidl_cb) override;
Return<void> useTripleFramebuffer(useTripleFramebuffer_cb _hidl_cb) override;
+ Return<void> useContextPriority(useContextPriority_cb _hidl_cb) override;
// Methods from ::android::hidl::base::V1_0::IBase follow.
diff --git a/configstore/1.0/default/surfaceflinger.mk b/configstore/1.0/default/surfaceflinger.mk
index 49314d7..5611e2e 100644
--- a/configstore/1.0/default/surfaceflinger.mk
+++ b/configstore/1.0/default/surfaceflinger.mk
@@ -12,3 +12,11 @@
ifeq ($(NUM_FRAMEBUFFER_SURFACE_BUFFERS),3)
LOCAL_CFLAGS += -DUSE_TRIPLE_FRAMEBUFFER
endif
+
+ifeq ($(TARGET_BOARD_PLATFORM),omap4)
+ LOCAL_CFLAGS += -DUSE_CONTEXT_PRIORITY=1
+endif
+
+ifeq ($(TARGET_BOARD_PLATFORM),s5pc110)
+ LOCAL_CFLAGS += -DUSE_CONTEXT_PRIORITY=1
+endif
diff --git a/tests/msgq/1.0/default/Android.bp b/tests/msgq/1.0/default/Android.bp
index 692edda..16018ac 100644
--- a/tests/msgq/1.0/default/Android.bp
+++ b/tests/msgq/1.0/default/Android.bp
@@ -1,3 +1,18 @@
+//
+// 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_library_shared {
name: "android.hardware.tests.msgq@1.0-impl",
defaults: ["hidl_defaults"],
@@ -5,6 +20,7 @@
proprietary: true,
srcs: [
"TestMsgQ.cpp",
+ "BenchmarkMsgQ.cpp"
],
shared_libs: [
"libbase",
@@ -18,3 +34,35 @@
"android.hidl.base@1.0",
],
}
+
+cc_test {
+ name: "android.hardware.tests.msgq@1.0-service-benchmark",
+ srcs: ["mq_benchmark_service.cpp"],
+ gtest: false,
+
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ "android.hardware.tests.msgq@1.0"
+ ],
+}
+
+cc_test {
+ name: "android.hardware.tests.msgq@1.0-service-test",
+ srcs: ["mq_test_service.cpp"],
+ gtest: false,
+
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "libhidlbase",
+ "libhidltransport",
+ "liblog",
+ "libutils",
+ "android.hardware.tests.msgq@1.0"
+ ],
+}
diff --git a/tests/msgq/1.0/default/BenchmarkMsgQ.cpp b/tests/msgq/1.0/default/BenchmarkMsgQ.cpp
new file mode 100644
index 0000000..43e6fcc
--- /dev/null
+++ b/tests/msgq/1.0/default/BenchmarkMsgQ.cpp
@@ -0,0 +1,156 @@
+/*
+ * 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 "BenchmarkMsgQ.h"
+#include <iostream>
+#include <thread>
+#include <fmq/MessageQueue.h>
+
+namespace android {
+namespace hardware {
+namespace tests {
+namespace msgq {
+namespace V1_0 {
+namespace implementation {
+
+// Methods from ::android::hardware::tests::msgq::V1_0::IBenchmarkMsgQ follow.
+Return<void> BenchmarkMsgQ::configureClientInboxSyncReadWrite(
+ configureClientInboxSyncReadWrite_cb _hidl_cb) {
+ static constexpr size_t kNumElementsInQueue = 16 * 1024;
+ mFmqOutbox = new (std::nothrow) android::hardware::MessageQueue<uint8_t,
+ kSynchronizedReadWrite>(kNumElementsInQueue);
+ if (mFmqOutbox == nullptr) {
+ _hidl_cb(false /* ret */, android::hardware::MQDescriptorSync<uint8_t>(
+ std::vector<android::hardware::GrantorDescriptor>(),
+ nullptr /* nhandle */, 0 /* size */));
+ } else {
+ _hidl_cb(true /* ret */, *mFmqOutbox->getDesc());
+ }
+
+ return Void();
+}
+
+Return<void> BenchmarkMsgQ::configureClientOutboxSyncReadWrite(
+ configureClientOutboxSyncReadWrite_cb _hidl_cb) {
+ static constexpr size_t kNumElementsInQueue = 16 * 1024;
+ mFmqInbox = new (std::nothrow) android::hardware::MessageQueue<uint8_t,
+ kSynchronizedReadWrite>(kNumElementsInQueue);
+ if ((mFmqInbox == nullptr) || (mFmqInbox->isValid() == false)) {
+ _hidl_cb(false /* ret */, android::hardware::MQDescriptorSync<uint8_t>(
+ std::vector<android::hardware::GrantorDescriptor>(),
+ nullptr /* nhandle */, 0 /* size */));
+ } else {
+ _hidl_cb(true /* ret */, *mFmqInbox->getDesc());
+ }
+
+ return Void();
+}
+
+Return<bool> BenchmarkMsgQ::requestWrite(int32_t count) {
+ uint8_t* data = new (std::nothrow) uint8_t[count];
+ for (int i = 0; i < count; i++) {
+ data[i] = i;
+ }
+ bool result = mFmqOutbox->write(data, count);
+ delete[] data;
+ return result;
+}
+
+Return<bool> BenchmarkMsgQ::requestRead(int32_t count) {
+ uint8_t* data = new (std::nothrow) uint8_t[count];
+ bool result = mFmqInbox->read(data, count);
+ delete[] data;
+ return result;
+}
+
+Return<void> BenchmarkMsgQ::benchmarkPingPong(uint32_t numIter) {
+ std::thread(QueuePairReadWrite<kSynchronizedReadWrite>, mFmqInbox,
+ mFmqOutbox, numIter)
+ .detach();
+ return Void();
+}
+
+Return<void> BenchmarkMsgQ::benchmarkServiceWriteClientRead(uint32_t numIter) {
+ if (mTimeData) delete[] mTimeData;
+ mTimeData = new (std::nothrow) int64_t[numIter];
+ std::thread(QueueWriter<kSynchronizedReadWrite>, mFmqOutbox,
+ mTimeData, numIter).detach();
+ return Void();
+}
+
+Return<void> BenchmarkMsgQ::sendTimeData(const hidl_vec<int64_t>& clientRcvTimeArray) {
+ int64_t accumulatedTime = 0;
+
+ for (uint32_t i = 0; i < clientRcvTimeArray.size(); i++) {
+ std::chrono::time_point<std::chrono::high_resolution_clock>
+ clientRcvTime((std::chrono::high_resolution_clock::duration(
+ clientRcvTimeArray[i])));
+ std::chrono::time_point<std::chrono::high_resolution_clock>serverSendTime(
+ (std::chrono::high_resolution_clock::duration(mTimeData[i])));
+ accumulatedTime += static_cast<int64_t>(
+ std::chrono::duration_cast<std::chrono::nanoseconds>(clientRcvTime -
+ serverSendTime).count());
+ }
+
+ accumulatedTime /= clientRcvTimeArray.size();
+ std::cout << "Average service to client write to read delay::"
+ << accumulatedTime << "ns" << std::endl;
+ return Void();
+}
+
+template <MQFlavor flavor>
+void BenchmarkMsgQ::QueueWriter(android::hardware::MessageQueue<uint8_t, flavor>* mFmqOutbox,
+ int64_t* mTimeData,
+ uint32_t numIter) {
+ uint8_t data[kPacketSize64];
+ uint32_t numWrites = 0;
+
+ while (numWrites < numIter) {
+ do {
+ mTimeData[numWrites] =
+ std::chrono::high_resolution_clock::now().time_since_epoch().count();
+ } while (mFmqOutbox->write(data, kPacketSize64) == false);
+ numWrites++;
+ }
+}
+
+template <MQFlavor flavor>
+void BenchmarkMsgQ::QueuePairReadWrite(
+ android::hardware::MessageQueue<uint8_t, flavor>* mFmqInbox,
+ android::hardware::MessageQueue<uint8_t, flavor>* mFmqOutbox,
+ uint32_t numIter) {
+ uint8_t data[kPacketSize64];
+ uint32_t numRoundTrips = 0;
+
+ while (numRoundTrips < numIter) {
+ while (mFmqInbox->read(data, kPacketSize64) == false)
+ ;
+ while (mFmqOutbox->write(data, kPacketSize64) == false)
+ ;
+ numRoundTrips++;
+ }
+}
+
+IBenchmarkMsgQ* HIDL_FETCH_IBenchmarkMsgQ(const char* /* name */) {
+ return new BenchmarkMsgQ();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace msgq
+} // namespace tests
+} // namespace hardware
+} // namespace android
diff --git a/tests/msgq/1.0/default/BenchmarkMsgQ.h b/tests/msgq/1.0/default/BenchmarkMsgQ.h
new file mode 100644
index 0000000..2cbe93c
--- /dev/null
+++ b/tests/msgq/1.0/default/BenchmarkMsgQ.h
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_HARDWARE_TESTS_MSGQ_V1_0_BENCHMARKMSGQ_H
+#define ANDROID_HARDWARE_TESTS_MSGQ_V1_0_BENCHMARKMSGQ_H
+
+#include <android/hardware/tests/msgq/1.0/IBenchmarkMsgQ.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+#include <fmq/MessageQueue.h>
+
+namespace android {
+namespace hardware {
+namespace tests {
+namespace msgq {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::tests::msgq::V1_0::IBenchmarkMsgQ;
+using ::android::hidl::base::V1_0::DebugInfo;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_memory;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+
+using android::hardware::kSynchronizedReadWrite;
+using android::hardware::MQFlavor;
+
+struct BenchmarkMsgQ : public IBenchmarkMsgQ {
+ /*
+ * The various packet sizes used are as follows.
+ */
+ enum PacketSizes {
+ kPacketSize64 = 64,
+ kPacketSize128 = 128,
+ kPacketSize256 = 256,
+ kPacketSize512 = 512,
+ kPacketSize1024 = 1024
+ };
+ // Methods from ::android::hardware::tests::msgq::V1_0::IBenchmarkMsgQ follow.
+ Return<void> configureClientInboxSyncReadWrite(configureClientInboxSyncReadWrite_cb _hidl_cb) override;
+ Return<void> configureClientOutboxSyncReadWrite(configureClientOutboxSyncReadWrite_cb _hidl_cb) override;
+ Return<bool> requestWrite(int32_t count) override;
+ Return<bool> requestRead(int32_t count) override;
+ Return<void> benchmarkPingPong(uint32_t numIter) override;
+ Return<void> benchmarkServiceWriteClientRead(uint32_t numIter) override;
+ Return<void> sendTimeData(const hidl_vec<int64_t>& timeData) override;
+
+ /*
+ * This method writes numIter packets into the mFmqOutbox queue
+ * and notes the time before each write in the mTimeData array. It will
+ * be used to calculate the average server to client write to read delay.
+ */
+ template <MQFlavor flavor>
+ static void QueueWriter(android::hardware::MessageQueue<uint8_t, flavor>*
+ mFmqOutbox, int64_t* mTimeData, uint32_t numIter);
+ /*
+ * The method reads a packet from the inbox queue and writes the same
+ * into the outbox queue. The client will calculate the average time taken
+ * for each iteration which consists of two write and two read operations.
+ */
+ template <MQFlavor flavor>
+ static void QueuePairReadWrite(
+ android::hardware::MessageQueue<uint8_t, flavor>* mFmqInbox,
+ android::hardware::MessageQueue<uint8_t, flavor>* mFmqOutbox,
+ uint32_t numIter);
+
+private:
+ android::hardware::MessageQueue<uint8_t, kSynchronizedReadWrite>* mFmqInbox;
+ android::hardware::MessageQueue<uint8_t, kSynchronizedReadWrite>* mFmqOutbox;
+ int64_t* mTimeData;
+};
+
+extern "C" IBenchmarkMsgQ* HIDL_FETCH_IBenchmarkMsgQ(const char* name);
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace msgq
+} // namespace tests
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_TESTS_MSGQ_V1_0_BENCHMARKMSGQ_H
diff --git a/tests/msgq/1.0/default/TestMsgQ.cpp b/tests/msgq/1.0/default/TestMsgQ.cpp
index 7cc4f5b..6fd4fc6 100644
--- a/tests/msgq/1.0/default/TestMsgQ.cpp
+++ b/tests/msgq/1.0/default/TestMsgQ.cpp
@@ -1,3 +1,19 @@
+/*
+ * 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 "TestMsgQ.h"
namespace android {
diff --git a/tests/msgq/1.0/default/TestMsgQ.h b/tests/msgq/1.0/default/TestMsgQ.h
index 760d931..86e4ac4 100644
--- a/tests/msgq/1.0/default/TestMsgQ.h
+++ b/tests/msgq/1.0/default/TestMsgQ.h
@@ -1,3 +1,19 @@
+/*
+ * 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.
+ */
+
#ifndef ANDROID_HARDWARE_TESTS_MSGQ_V1_0_TESTMSGQ_H
#define ANDROID_HARDWARE_TESTS_MSGQ_V1_0_TESTMSGQ_H
diff --git a/tests/msgq/1.0/default/mq_benchmark_service.cpp b/tests/msgq/1.0/default/mq_benchmark_service.cpp
new file mode 100644
index 0000000..b9be81b
--- /dev/null
+++ b/tests/msgq/1.0/default/mq_benchmark_service.cpp
@@ -0,0 +1,28 @@
+/*
+* 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 "FMQ_Benchmarks"
+
+#include <android/hardware/tests/msgq/1.0/IBenchmarkMsgQ.h>
+
+#include <hidl/LegacySupport.h>
+
+using android::hardware::tests::msgq::V1_0::IBenchmarkMsgQ;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+ return defaultPassthroughServiceImplementation<IBenchmarkMsgQ>();
+}
diff --git a/tests/msgq/1.0/default/mq_test_service.cpp b/tests/msgq/1.0/default/mq_test_service.cpp
new file mode 100644
index 0000000..b5cb662
--- /dev/null
+++ b/tests/msgq/1.0/default/mq_test_service.cpp
@@ -0,0 +1,28 @@
+/*
+* 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 "FMQ_UnitTests"
+
+#include <android/hardware/tests/msgq/1.0/ITestMsgQ.h>
+
+#include <hidl/LegacySupport.h>
+
+using android::hardware::tests::msgq::V1_0::ITestMsgQ;
+using android::hardware::defaultPassthroughServiceImplementation;
+
+int main() {
+ return defaultPassthroughServiceImplementation<ITestMsgQ>();
+}
diff --git a/wifi/1.0/default/hidl_struct_util.cpp b/wifi/1.0/default/hidl_struct_util.cpp
index a89f8c0..fb93c5a 100644
--- a/wifi/1.0/default/hidl_struct_util.cpp
+++ b/wifi/1.0/default/hidl_struct_util.cpp
@@ -706,11 +706,17 @@
hidl_stats->iface.wmeVoPktStats.retries =
legacy_stats.iface.ac[legacy_hal::WIFI_AC_VO].retries;
// radio legacy_stats conversion.
- hidl_stats->radio.onTimeInMs = legacy_stats.radio.on_time;
- hidl_stats->radio.txTimeInMs = legacy_stats.radio.tx_time;
- hidl_stats->radio.rxTimeInMs = legacy_stats.radio.rx_time;
- hidl_stats->radio.onTimeInMsForScan = legacy_stats.radio.on_time_scan;
- hidl_stats->radio.txTimeInMsPerLevel = legacy_stats.radio_tx_time_per_levels;
+ std::vector<StaLinkLayerRadioStats> hidl_radios_stats;
+ for (const auto& legacy_radio_stats : legacy_stats.radios) {
+ StaLinkLayerRadioStats hidl_radio_stats;
+ hidl_radio_stats.onTimeInMs = legacy_radio_stats.stats.on_time;
+ hidl_radio_stats.txTimeInMs = legacy_radio_stats.stats.tx_time;
+ hidl_radio_stats.rxTimeInMs = legacy_radio_stats.stats.rx_time;
+ hidl_radio_stats.onTimeInMsForScan = legacy_radio_stats.stats.on_time_scan;
+ hidl_radio_stats.txTimeInMsPerLevel = legacy_radio_stats.tx_time_per_levels;
+ hidl_radios_stats.push_back(hidl_radio_stats);
+ }
+ hidl_stats->radios = hidl_radios_stats;
// Timestamp in the HAL wrapper here since it's not provided in the legacy
// HAL API.
hidl_stats->timeStampInMs = uptimeMillis();
diff --git a/wifi/1.0/default/wifi_legacy_hal.cpp b/wifi/1.0/default/wifi_legacy_hal.cpp
index f902e64..5fc0228 100644
--- a/wifi/1.0/default/wifi_legacy_hal.cpp
+++ b/wifi/1.0/default/wifi_legacy_hal.cpp
@@ -601,33 +601,37 @@
LinkLayerStats link_stats{};
LinkLayerStats* link_stats_ptr = &link_stats;
- on_link_layer_stats_result_internal_callback = [&link_stats_ptr](
- wifi_request_id /* id */,
- wifi_iface_stat* iface_stats_ptr,
- int num_radios,
- wifi_radio_stat* radio_stats_ptr) {
- if (iface_stats_ptr != nullptr) {
- link_stats_ptr->iface = *iface_stats_ptr;
- link_stats_ptr->iface.num_peers = 0;
- } else {
- LOG(ERROR) << "Invalid iface stats in link layer stats";
- }
- if (num_radios == 1 && radio_stats_ptr != nullptr) {
- link_stats_ptr->radio = *radio_stats_ptr;
- // Copy over the tx level array to the separate vector.
- if (radio_stats_ptr->num_tx_levels > 0 &&
- radio_stats_ptr->tx_time_per_levels != nullptr) {
- link_stats_ptr->radio_tx_time_per_levels.assign(
- radio_stats_ptr->tx_time_per_levels,
- radio_stats_ptr->tx_time_per_levels +
- radio_stats_ptr->num_tx_levels);
- }
- link_stats_ptr->radio.num_tx_levels = 0;
- link_stats_ptr->radio.tx_time_per_levels = nullptr;
- } else {
- LOG(ERROR) << "Invalid radio stats in link layer stats";
- }
- };
+ on_link_layer_stats_result_internal_callback =
+ [&link_stats_ptr](wifi_request_id /* id */,
+ wifi_iface_stat* iface_stats_ptr,
+ int num_radios,
+ wifi_radio_stat* radio_stats_ptr) {
+ if (iface_stats_ptr != nullptr) {
+ link_stats_ptr->iface = *iface_stats_ptr;
+ link_stats_ptr->iface.num_peers = 0;
+ } else {
+ LOG(ERROR) << "Invalid iface stats in link layer stats";
+ }
+ if (num_radios <= 0 || radio_stats_ptr == nullptr) {
+ LOG(ERROR) << "Invalid radio stats in link layer stats";
+ return;
+ }
+ for (int i = 0; i < num_radios; i++) {
+ LinkLayerRadioStats radio;
+ radio.stats = radio_stats_ptr[i];
+ // Copy over the tx level array to the separate vector.
+ if (radio_stats_ptr[i].num_tx_levels > 0 &&
+ radio_stats_ptr[i].tx_time_per_levels != nullptr) {
+ radio.tx_time_per_levels.assign(
+ radio_stats_ptr[i].tx_time_per_levels,
+ radio_stats_ptr[i].tx_time_per_levels +
+ radio_stats_ptr[i].num_tx_levels);
+ }
+ radio.stats.num_tx_levels = 0;
+ radio.stats.tx_time_per_levels = nullptr;
+ link_stats_ptr->radios.push_back(radio);
+ }
+ };
wifi_error status = global_func_table_.wifi_get_link_stats(
0, wlan_interface_handle_, {onSyncLinkLayerStatsResult});
diff --git a/wifi/1.0/default/wifi_legacy_hal.h b/wifi/1.0/default/wifi_legacy_hal.h
index c8fd5bd..576dfe6 100644
--- a/wifi/1.0/default/wifi_legacy_hal.h
+++ b/wifi/1.0/default/wifi_legacy_hal.h
@@ -49,10 +49,14 @@
// The |wifi_radio_stat.tx_time_per_levels| stats is provided as a pointer in
// |wifi_radio_stat| structure in the legacy HAL API. Separate that out
// into a separate return element to avoid passing pointers around.
+struct LinkLayerRadioStats {
+ wifi_radio_stat stats;
+ std::vector<uint32_t> tx_time_per_levels;
+};
+
struct LinkLayerStats {
wifi_iface_stat iface;
- wifi_radio_stat radio;
- std::vector<uint32_t> radio_tx_time_per_levels;
+ std::vector<LinkLayerRadioStats> radios;
};
#pragma GCC diagnostic pop
@@ -285,7 +289,7 @@
// Opaque handle to be used for all wlan0 interface specific operations.
wifi_interface_handle wlan_interface_handle_;
// Flag to indicate if we have initiated the cleanup of legacy HAL.
- bool awaiting_event_loop_termination_;
+ std::atomic<bool> awaiting_event_loop_termination_;
// Flag to indicate if the legacy HAL has been started.
bool is_started_;
wifi_system::InterfaceTool iface_tool_;
diff --git a/wifi/1.0/types.hal b/wifi/1.0/types.hal
index d90d5be..d3845c9 100644
--- a/wifi/1.0/types.hal
+++ b/wifi/1.0/types.hal
@@ -143,7 +143,7 @@
/**
* TimeStamp in milliseconds (ms).
*/
-typedef uint32_t TimeStampInMs;
+typedef uint64_t TimeStampInMs;
/**
* TimeStamp in microseconds (us).
@@ -478,7 +478,7 @@
*/
struct StaLinkLayerStats {
StaLinkLayerIfaceStats iface;
- StaLinkLayerRadioStats radio;
+ vec<StaLinkLayerRadioStats> radios;
/**
* TimeStamp for each stats sample.
* This is the absolute milliseconds from boot when these stats were