Merge "Add VTS coverage for TWT methods" into main
diff --git a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
index ea59771..cef0ea6 100644
--- a/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
+++ b/audio/aidl/default/r_submix/StreamRemoteSubmix.cpp
@@ -77,17 +77,15 @@
}
::android::status_t StreamRemoteSubmix::drain(StreamDescriptor::DrainMode) {
- usleep(1000);
return ::android::OK;
}
::android::status_t StreamRemoteSubmix::flush() {
- usleep(1000);
- return ::android::OK;
+ // TODO(b/372951987): consider if this needs to be done from 'StreamInWorkerLogic::cycle'.
+ return mIsInput ? standby() : ::android::OK;
}
::android::status_t StreamRemoteSubmix::pause() {
- usleep(1000);
return ::android::OK;
}
diff --git a/audio/aidl/default/r_submix/SubmixRoute.cpp b/audio/aidl/default/r_submix/SubmixRoute.cpp
index 325a012..445b1d3 100644
--- a/audio/aidl/default/r_submix/SubmixRoute.cpp
+++ b/audio/aidl/default/r_submix/SubmixRoute.cpp
@@ -134,10 +134,10 @@
// - the peer input is in standby AFTER having been active.
// We DO block if:
// - the input was never activated to avoid discarding first frames in the pipe in case capture
-// start was delayed
+// start was delayed
bool SubmixRoute::shouldBlockWrite() {
std::lock_guard guard(mLock);
- return (mStreamInOpen || (mStreamInStandby && (mReadCounterFrames != 0)));
+ return mStreamInOpen && (!mStreamInStandby || mReadCounterFrames == 0);
}
long SubmixRoute::updateReadCounterFrames(size_t frameCount) {
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index 93c2a61..750e54d 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -938,6 +938,8 @@
LOG(DEBUG) << __func__;
return "";
}
+ const std::vector<int8_t>& getData() const { return mData; }
+ void fillData(int8_t filler) { std::fill(mData.begin(), mData.end(), filler); }
std::optional<StreamDescriptor::Command> maybeGetNextCommand(int* actualSize = nullptr) {
TransitionTrigger trigger = mDriver->getNextTrigger(mData.size(), actualSize);
if (StreamEventReceiver::Event* expEvent =
@@ -1007,6 +1009,8 @@
StreamReaderLogic(const StreamContext& context, StreamLogicDriver* driver,
StreamEventReceiver* eventReceiver)
: StreamCommonLogic(context, driver, eventReceiver) {}
+ // Should only be called after the worker has joined.
+ const std::vector<int8_t>& getData() const { return StreamCommonLogic::getData(); }
protected:
Status cycle() override {
@@ -1072,6 +1076,7 @@
if (const size_t readCount =
!isMmapped() ? getDataMQ()->availableToRead() : reply.fmqByteCount;
readCount > 0) {
+ fillData(-1);
if (isMmapped() ? readDataFromMmap(readCount) : readDataFromMQ(readCount)) {
goto checkAcceptedReply;
}
@@ -1093,6 +1098,8 @@
StreamWriterLogic(const StreamContext& context, StreamLogicDriver* driver,
StreamEventReceiver* eventReceiver)
: StreamCommonLogic(context, driver, eventReceiver) {}
+ // Should only be called after the worker has joined.
+ const std::vector<int8_t>& getData() const { return StreamCommonLogic::getData(); }
protected:
Status cycle() override {
@@ -1109,6 +1116,14 @@
return Status::ABORT;
}
if (actualSize != 0) {
+ if (command.getTag() == StreamDescriptor::Command::burst) {
+ fillData(mBurstIteration);
+ if (mBurstIteration < std::numeric_limits<int8_t>::max()) {
+ mBurstIteration++;
+ } else {
+ mBurstIteration = 0;
+ }
+ }
if (isMmapped() ? !writeDataToMmap() : !writeDataToMQ()) {
return Status::ABORT;
}
@@ -1167,6 +1182,9 @@
LOG(ERROR) << __func__ << ": unacceptable reply: " << reply.toString();
return Status::ABORT;
}
+
+ private:
+ int8_t mBurstIteration = 1;
};
using StreamWriter = StreamWorker<StreamWriterLogic>;
@@ -2859,10 +2877,12 @@
ASSERT_NO_FATAL_FAILURE(mStream->SetUpStream(module, getMinimumStreamBufferSizeFrames()));
}
- void SetUpStreamForDevicePort(IModule* module, ModuleConfig* moduleConfig,
- const AudioPort& devicePort, bool connectedOnly = false) {
- ASSERT_NO_FATAL_FAILURE(
- SetUpPortConfigForDevicePort(module, moduleConfig, devicePort, connectedOnly));
+ void SetUpStreamForDevicePort(
+ IModule* module, ModuleConfig* moduleConfig, const AudioPort& devicePort,
+ bool connectedOnly = false,
+ const std::optional<AudioDeviceAddress>& connectionAddress = std::nullopt) {
+ ASSERT_NO_FATAL_FAILURE(SetUpPortConfigForDevicePort(module, moduleConfig, devicePort,
+ connectedOnly, connectionAddress));
if (!mSkipTestReason.empty()) return;
ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
}
@@ -2898,6 +2918,23 @@
if (!mSkipTestReason.empty()) return;
ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
}
+ void SetUpStreamForNewMixPortConfig(IModule* module, ModuleConfig*,
+ const AudioPortConfig& existingMixPortConfig,
+ const AudioPortConfig& existingDevicePortConfig) {
+ auto mixPortConfig = existingMixPortConfig;
+ mixPortConfig.id = 0;
+ mMixPortConfig = std::make_unique<WithAudioPortConfig>(mixPortConfig);
+ ASSERT_NO_FATAL_FAILURE(mMixPortConfig->SetUp(module));
+ mDevicePortConfig = std::make_unique<WithAudioPortConfig>(existingDevicePortConfig);
+ ASSERT_NO_FATAL_FAILURE(mDevicePortConfig->SetUp(module));
+ mDevice = existingDevicePortConfig.ext.get<AudioPortExt::device>().device;
+ mPatch = std::make_unique<WithAudioPatch>(mIsInput, mMixPortConfig->get(),
+ mDevicePortConfig->get());
+ ASSERT_NO_FATAL_FAILURE(mPatch->SetUp(module));
+ mStream = std::make_unique<WithStream<Stream>>(mMixPortConfig->get());
+ ASSERT_NO_FATAL_FAILURE(mStream->SetUpPortConfig(module));
+ ASSERT_NO_FATAL_FAILURE(SetUpStream(module));
+ }
void SetUpPatchForMixPortConfig(IModule* module, ModuleConfig* moduleConfig,
const AudioPortConfig& mixPortConfig) {
constexpr bool connectedOnly = true;
@@ -2929,6 +2966,7 @@
}
const AudioDevice& getDevice() const { return mDevice; }
+ const AudioPortConfig& getDevicePortConfig() const { return mDevicePortConfig->get(); }
int32_t getMinimumStreamBufferSizeFrames() const {
return mPatch->getMinimumStreamBufferSizeFrames();
}
@@ -2944,7 +2982,8 @@
private:
void SetUpDevicePort(IModule* module, ModuleConfig* moduleConfig,
const std::set<int32_t>& devicePortIds, bool connectedOnly,
- std::optional<AudioPort>* connectedDevicePort) {
+ std::optional<AudioPort>* connectedDevicePort,
+ const std::optional<AudioDeviceAddress>& connectionAddress) {
const auto attachedDevicePorts = moduleConfig->getAttachedDevicePorts();
if (auto it = findAny<AudioPort>(attachedDevicePorts, devicePortIds);
it != attachedDevicePorts.end()) {
@@ -2961,7 +3000,12 @@
const auto externalDevicePorts = moduleConfig->getExternalDevicePorts();
if (auto it = findAny<AudioPort>(externalDevicePorts, devicePortIds);
it != externalDevicePorts.end()) {
- AudioPort portWithData = GenerateUniqueDeviceAddress(*it);
+ AudioPort portWithData = *it;
+ if (connectionAddress.has_value()) {
+ portWithData.ext.get<AudioPortExt::Tag::device>().device.address =
+ *connectionAddress;
+ }
+ portWithData = GenerateUniqueDeviceAddress(portWithData);
mPortConnected = std::make_unique<WithDevicePortConnectedState>(portWithData);
ASSERT_NO_FATAL_FAILURE(mPortConnected->SetUp(module, moduleConfig));
*connectedDevicePort = mPortConnected->get();
@@ -2980,9 +3024,9 @@
LOG(DEBUG) << __func__ << ": " << mSkipTestReason;
return;
};
- ASSERT_NO_FATAL_FAILURE(SetUpDevicePort(module, moduleConfig,
- extractIds<AudioPort>(devicePorts), connectedOnly,
- connectedDevicePort));
+ ASSERT_NO_FATAL_FAILURE(SetUpDevicePort(
+ module, moduleConfig, extractIds<AudioPort>(devicePorts), connectedOnly,
+ connectedDevicePort, std::nullopt /*connectionAddress*/));
if (!connectedDevicePort->has_value()) {
mSkipTestReason = std::string("Unable to find a device port pair for mix port id ")
.append(std::to_string(mixPort.id));
@@ -2990,11 +3034,14 @@
return;
}
}
- void SetUpPortConfigForDevicePort(IModule* module, ModuleConfig* moduleConfig,
- const AudioPort& devicePort, bool connectedOnly) {
+ void SetUpPortConfigForDevicePort(
+ IModule* module, ModuleConfig* moduleConfig, const AudioPort& devicePort,
+ bool connectedOnly,
+ const std::optional<AudioDeviceAddress>& connectionAddress = std::nullopt) {
std::optional<AudioPort> connectedDevicePort;
ASSERT_NO_FATAL_FAILURE(SetUpDevicePort(module, moduleConfig, {devicePort.id},
- connectedOnly, &connectedDevicePort));
+ connectedOnly, &connectedDevicePort,
+ connectionAddress));
if (!connectedDevicePort.has_value()) {
mSkipTestReason = std::string("Device port id ")
.append(std::to_string(devicePort.id))
@@ -3135,7 +3182,8 @@
};
// Defined later together with state transition sequences.
-std::shared_ptr<StateSequence> makeBurstCommands(bool isSync);
+std::shared_ptr<StateSequence> makeBurstCommands(bool isSync, size_t burstCount = 10,
+ bool standbyInputWhenDone = false);
// Certain types of ports can not be used without special preconditions.
static bool skipStreamIoTestForMixPortConfig(const AudioPortConfig& portConfig) {
@@ -3160,10 +3208,11 @@
public:
explicit StreamFixtureWithWorker(bool isSync) : mIsSync(isSync) {}
- void SetUp(IModule* module, ModuleConfig* moduleConfig, const AudioPort& devicePort) {
+ void SetUp(IModule* module, ModuleConfig* moduleConfig, const AudioPort& devicePort,
+ const std::optional<AudioDeviceAddress>& connectionAddress = std::nullopt) {
mStream = std::make_unique<StreamFixture<Stream>>();
- ASSERT_NO_FATAL_FAILURE(
- mStream->SetUpStreamForDevicePort(module, moduleConfig, devicePort));
+ ASSERT_NO_FATAL_FAILURE(mStream->SetUpStreamForDevicePort(
+ module, moduleConfig, devicePort, false /*connectedOnly*/, connectionAddress));
MaybeSetSkipTestReason();
}
@@ -3175,26 +3224,42 @@
MaybeSetSkipTestReason();
}
- void SendBurstCommands(bool validatePosition = true) {
- ASSERT_NO_FATAL_FAILURE(StartWorkerToSendBurstCommands());
+ void SetUp(IModule* module, ModuleConfig* moduleConfig,
+ const AudioPortConfig& existingMixPortConfig,
+ const AudioPortConfig& existingDevicePortConfig) {
+ mStream = std::make_unique<StreamFixture<Stream>>();
+ ASSERT_NO_FATAL_FAILURE(mStream->SetUpStreamForNewMixPortConfig(
+ module, moduleConfig, existingMixPortConfig, existingDevicePortConfig));
+ MaybeSetSkipTestReason();
+ }
+
+ void SendBurstCommands(bool validatePosition = true, size_t burstCount = 10,
+ bool standbyInputWhenDone = false) {
+ ASSERT_NO_FATAL_FAILURE(StartWorkerToSendBurstCommands(burstCount, standbyInputWhenDone));
ASSERT_NO_FATAL_FAILURE(JoinWorkerAfterBurstCommands(validatePosition));
}
- void StartWorkerToSendBurstCommands() {
+ void StartWorkerToSendBurstCommands(size_t burstCount = 10, bool standbyInputWhenDone = false) {
+ if (!IOTraits<Stream>::is_input) {
+ ASSERT_FALSE(standbyInputWhenDone) << "Only supported for input";
+ }
const StreamContext* context = mStream->getStreamContext();
mWorkerDriver = std::make_unique<StreamLogicDefaultDriver>(
- makeBurstCommands(mIsSync), context->getFrameSizeBytes(), context->isMmapped());
+ makeBurstCommands(mIsSync, burstCount, standbyInputWhenDone),
+ context->getFrameSizeBytes(), context->isMmapped());
mWorker = std::make_unique<typename IOTraits<Stream>::Worker>(
*context, mWorkerDriver.get(), mStream->getStreamEventReceiver());
LOG(DEBUG) << __func__ << ": starting " << IOTraits<Stream>::directionStr << " worker...";
ASSERT_TRUE(mWorker->start());
}
- void JoinWorkerAfterBurstCommands(bool validatePosition = true) {
- // Must call 'prepareToClose' before attempting to join because the stream may be stuck.
- std::shared_ptr<IStreamCommon> common;
- ASSERT_IS_OK(mStream->getStream()->getStreamCommon(&common));
- ASSERT_IS_OK(common->prepareToClose());
+ void JoinWorkerAfterBurstCommands(bool validatePosition = true,
+ bool callPrepareToClose = true) {
+ if (callPrepareToClose) {
+ std::shared_ptr<IStreamCommon> common;
+ ASSERT_IS_OK(mStream->getStream()->getStreamCommon(&common));
+ ASSERT_IS_OK(common->prepareToClose());
+ }
LOG(DEBUG) << __func__ << ": joining " << IOTraits<Stream>::directionStr << " worker...";
mWorker->join();
EXPECT_FALSE(mWorker->hasError()) << mWorker->getError();
@@ -3205,6 +3270,7 @@
EXPECT_FALSE(mWorkerDriver->hasObservableRetrogradePosition());
EXPECT_FALSE(mWorkerDriver->hasHardwareRetrogradePosition());
}
+ mLastData = mWorker->getData();
mWorker.reset();
mWorkerDriver.reset();
}
@@ -3212,6 +3278,9 @@
void TeardownPatch() { mStream->TeardownPatch(); }
const AudioDevice& getDevice() const { return mStream->getDevice(); }
+ const AudioPortConfig& getDevicePortConfig() const { return mStream->getDevicePortConfig(); }
+ const std::vector<int8_t>& getLastData() const { return mLastData; }
+ const AudioPortConfig& getPortConfig() const { return mStream->getPortConfig(); }
Stream* getStream() const { return mStream->getStream(); }
std::string skipTestReason() const {
return !mSkipTestReason.empty() ? mSkipTestReason : mStream->skipTestReason();
@@ -3229,6 +3298,7 @@
std::unique_ptr<StreamFixture<Stream>> mStream;
std::unique_ptr<StreamLogicDefaultDriver> mWorkerDriver;
std::unique_ptr<typename IOTraits<Stream>::Worker> mWorker;
+ std::vector<int8_t> mLastData;
};
template <typename Stream>
@@ -4576,15 +4646,20 @@
// TODO: Add async test cases for input once it is implemented.
-std::shared_ptr<StateSequence> makeBurstCommands(bool isSync) {
+std::shared_ptr<StateSequence> makeBurstCommands(bool isSync, size_t burstCount,
+ bool standbyInputWhenDone) {
using State = StreamDescriptor::State;
auto d = std::make_unique<StateDag>();
- StateDag::Node last = d->makeFinalNode(State::ACTIVE);
+ StateDag::Node active = d->makeFinalNode(State::ACTIVE);
+ StateDag::Node paused = d->makeNodes({std::make_pair(State::ACTIVE, kPauseCommand),
+ std::make_pair(State::PAUSED, kFlushCommand)},
+ State::STANDBY);
+ StateDag::Node& last = standbyInputWhenDone ? paused : active;
if (isSync) {
StateDag::Node idle = d->makeNode(
State::IDLE, kBurstCommand,
// Use several bursts to ensure that the driver starts reporting the position.
- d->makeNodes(State::ACTIVE, kBurstCommand, 10, last));
+ d->makeNodes(State::ACTIVE, kBurstCommand, burstCount, last));
d->makeNode(State::STANDBY, kStartCommand, idle);
} else {
StateDag::Node active2 = d->makeNode(State::ACTIVE, kBurstCommand, last);
@@ -4949,49 +5024,69 @@
public:
WithRemoteSubmix() : mStream(true /*isSync*/) {}
explicit WithRemoteSubmix(AudioDeviceAddress address)
- : mStream(true /*isSync*/), mAddress(address) {}
+ : mStream(true /*isSync*/), mAddress(address) {
+ LOG(DEBUG) << __func__ << ": Creating " << IOTraits<Stream>::directionStr
+ << " stream for: " << mAddress.value_or(AudioDeviceAddress{}).toString();
+ }
WithRemoteSubmix(const WithRemoteSubmix&) = delete;
WithRemoteSubmix& operator=(const WithRemoteSubmix&) = delete;
+ ~WithRemoteSubmix() {
+ LOG(DEBUG) << __func__ << ": Deleting " << IOTraits<Stream>::directionStr
+ << " stream for: " << mAddress.value_or(AudioDeviceAddress{}).toString();
+ }
- static std::optional<AudioPort> getRemoteSubmixAudioPort(
- ModuleConfig* moduleConfig,
- const std::optional<AudioDeviceAddress>& address = std::nullopt) {
+ static std::optional<AudioPort> getRemoteSubmixAudioPort(ModuleConfig* moduleConfig) {
auto ports =
moduleConfig->getRemoteSubmixPorts(IOTraits<Stream>::is_input, true /*singlePort*/);
if (ports.empty()) return {};
- AudioPort port = ports.front();
- if (address) {
- port.ext.template get<AudioPortExt::Tag::device>().device.address = address.value();
- }
- return port;
+ return ports.front();
}
void SetUp(IModule* module, ModuleConfig* moduleConfig) {
- auto devicePort = getRemoteSubmixAudioPort(moduleConfig, mAddress);
+ auto devicePort = getRemoteSubmixAudioPort(moduleConfig);
ASSERT_TRUE(devicePort.has_value()) << "Device port for remote submix device not found";
- ASSERT_NO_FATAL_FAILURE(mStream.SetUp(module, moduleConfig, *devicePort));
+ ASSERT_NO_FATAL_FAILURE(mStream.SetUp(module, moduleConfig, *devicePort, mAddress));
mAddress = mStream.getDevice().address;
}
-
- void StartWorkerToSendBurstCommands() {
- ASSERT_NO_FATAL_FAILURE(mStream.StartWorkerToSendBurstCommands());
+ void SetUp(IModule* module, ModuleConfig* moduleConfig,
+ const AudioPortConfig& existingMixPortConfig,
+ const AudioPortConfig& existingDevicePortConfig) {
+ ASSERT_NO_FATAL_FAILURE(mStream.SetUp(module, moduleConfig, existingMixPortConfig,
+ existingDevicePortConfig));
+ mAddress = mStream.getDevice().address;
+ }
+ void StartWorkerToSendBurstCommands(size_t burstCount = 10, bool standbyInputWhenDone = false) {
+ ASSERT_NO_FATAL_FAILURE(
+ mStream.StartWorkerToSendBurstCommands(burstCount, standbyInputWhenDone));
}
- void JoinWorkerAfterBurstCommands() {
- ASSERT_NO_FATAL_FAILURE(mStream.JoinWorkerAfterBurstCommands());
+ void JoinWorkerAfterBurstCommands(bool callPrepareToCloseBeforeJoin) {
+ ASSERT_NO_FATAL_FAILURE(mStream.JoinWorkerAfterBurstCommands(
+ true /*validatePositionIncrease*/, callPrepareToCloseBeforeJoin));
}
- void SendBurstCommands() {
- ASSERT_NO_FATAL_FAILURE(mStream.StartWorkerToSendBurstCommands());
- ASSERT_NO_FATAL_FAILURE(mStream.JoinWorkerAfterBurstCommands());
+ void JoinWorkerAfterBurstCommands(bool validatePositionIncrease,
+ bool callPrepareToCloseBeforeJoin) {
+ ASSERT_NO_FATAL_FAILURE(mStream.JoinWorkerAfterBurstCommands(validatePositionIncrease,
+ callPrepareToCloseBeforeJoin));
+ }
+
+ void SendBurstCommands(bool callPrepareToCloseBeforeJoin, size_t burstCount = 10,
+ bool standbyInputWhenDone = false) {
+ ASSERT_NO_FATAL_FAILURE(StartWorkerToSendBurstCommands(burstCount, standbyInputWhenDone));
+ // When 'burstCount == 0', there is no "previous" frame count, thus the check for
+ // the position increase fails.
+ ASSERT_NO_FATAL_FAILURE(JoinWorkerAfterBurstCommands(
+ burstCount > 0 /*validatePositionIncrease*/, callPrepareToCloseBeforeJoin));
}
std::optional<AudioDeviceAddress> getAudioDeviceAddress() const { return mAddress; }
+ const AudioPortConfig& getDevicePortConfig() const { return mStream.getDevicePortConfig(); }
+ int8_t getLastBurstIteration() const { return mStream.getLastData()[0]; }
+ const AudioPortConfig& getPortConfig() const { return mStream.getPortConfig(); }
std::string skipTestReason() const { return mStream.skipTestReason(); }
private:
- void SetUp(IModule* module, ModuleConfig* moduleConfig, const AudioPort& devicePort) {}
-
StreamFixtureWithWorker<Stream> mStream;
std::optional<AudioDeviceAddress> mAddress;
};
@@ -5007,77 +5102,130 @@
}
ASSERT_NO_FATAL_FAILURE(SetUpModuleConfig());
}
+
+ void TearDown() override {
+ streamIn.reset();
+ streamOut.reset();
+ }
+
+ void CreateOutputStream() {
+ streamOut = std::make_unique<WithRemoteSubmix<IStreamOut>>();
+ ASSERT_NO_FATAL_FAILURE(streamOut->SetUp(module.get(), moduleConfig.get()));
+ // Note: any issue with connection attempts is considered as a problem.
+ ASSERT_EQ("", streamOut->skipTestReason());
+ ASSERT_TRUE(streamOut->getAudioDeviceAddress().has_value());
+ }
+
+ void CreateInputStream(const std::optional<AudioDeviceAddress>& address = std::nullopt) {
+ if (address.has_value()) {
+ streamIn = std::make_unique<WithRemoteSubmix<IStreamIn>>(address.value());
+ } else {
+ ASSERT_TRUE(streamOut->getAudioDeviceAddress().has_value());
+ streamIn = std::make_unique<WithRemoteSubmix<IStreamIn>>(
+ streamOut->getAudioDeviceAddress().value());
+ }
+ ASSERT_NO_FATAL_FAILURE(streamIn->SetUp(module.get(), moduleConfig.get()));
+ ASSERT_EQ("", streamIn->skipTestReason());
+ auto inAddress = streamIn->getAudioDeviceAddress();
+ ASSERT_TRUE(inAddress.has_value());
+ if (address.has_value()) {
+ if (address.value() != AudioDeviceAddress{}) {
+ ASSERT_EQ(address.value(), inAddress.value());
+ }
+ } else {
+ ASSERT_EQ(streamOut->getAudioDeviceAddress().value(), inAddress.value());
+ }
+ }
+
+ std::unique_ptr<WithRemoteSubmix<IStreamOut>> streamOut;
+ std::unique_ptr<WithRemoteSubmix<IStreamIn>> streamIn;
};
TEST_P(AudioModuleRemoteSubmix, OutputDoesNotBlockWhenNoInput) {
- WithRemoteSubmix<IStreamOut> streamOut;
- ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
- // Note: here and in other tests any issue with connection attempts is considered as a problem.
- ASSERT_EQ("", streamOut.skipTestReason());
- ASSERT_NO_FATAL_FAILURE(streamOut.SendBurstCommands());
+ ASSERT_NO_FATAL_FAILURE(CreateOutputStream());
+ ASSERT_NO_FATAL_FAILURE(streamOut->SendBurstCommands(false /*callPrepareToCloseBeforeJoin*/));
}
-TEST_P(AudioModuleRemoteSubmix, OutputDoesNotBlockWhenInputStuck) {
- WithRemoteSubmix<IStreamOut> streamOut;
- ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
- ASSERT_EQ("", streamOut.skipTestReason());
- auto address = streamOut.getAudioDeviceAddress();
- ASSERT_TRUE(address.has_value());
+TEST_P(AudioModuleRemoteSubmix, OutputDoesNotBlockWhenInputInStandby) {
+ if (int32_t version; module->getInterfaceVersion(&version).isOk() && version < 3) {
+ GTEST_SKIP() << "Default remote submix implementation <V3 could not pass this test";
+ }
+ ASSERT_NO_FATAL_FAILURE(CreateOutputStream());
+ ASSERT_NO_FATAL_FAILURE(CreateInputStream());
+ ASSERT_NO_FATAL_FAILURE(streamOut->StartWorkerToSendBurstCommands());
+ // Send just 1 burst command. This triggers the condition "input is in standby after
+ // being active." The output must flush the fifo before writing to avoid being blocked.
+ ASSERT_NO_FATAL_FAILURE(
+ streamIn->StartWorkerToSendBurstCommands(1, true /*stanbyInputWhenDone*/));
+ // The output must be able to close without shutting down the pipe first (due to a call
+ // to 'prepareToClose').
+ ASSERT_NO_FATAL_FAILURE(
+ streamOut->JoinWorkerAfterBurstCommands(false /*callPrepareToCloseBeforeJoin*/));
+ ASSERT_NO_FATAL_FAILURE(
+ streamIn->JoinWorkerAfterBurstCommands(false /*callPrepareToCloseBeforeJoin*/));
+}
- WithRemoteSubmix<IStreamIn> streamIn(address.value());
- ASSERT_NO_FATAL_FAILURE(streamIn.SetUp(module.get(), moduleConfig.get()));
- ASSERT_EQ("", streamIn.skipTestReason());
+TEST_P(AudioModuleRemoteSubmix, BlockedOutputUnblocksOnClose) {
+ ASSERT_NO_FATAL_FAILURE(CreateOutputStream());
+ ASSERT_NO_FATAL_FAILURE(CreateInputStream());
+ ASSERT_NO_FATAL_FAILURE(streamOut->StartWorkerToSendBurstCommands());
+ // Send just 3 burst command, but do not enter standby. This is a stalled input.
+ ASSERT_NO_FATAL_FAILURE(streamIn->StartWorkerToSendBurstCommands(3));
+ ASSERT_NO_FATAL_FAILURE(
+ streamOut->JoinWorkerAfterBurstCommands(true /*callPrepareToCloseBeforeJoin*/));
+ ASSERT_NO_FATAL_FAILURE(
+ streamIn->JoinWorkerAfterBurstCommands(false /*callPrepareToCloseBeforeJoin*/));
+}
- ASSERT_NO_FATAL_FAILURE(streamOut.SendBurstCommands());
+TEST_P(AudioModuleRemoteSubmix, OutputBlocksUntilInputStarts) {
+ ASSERT_NO_FATAL_FAILURE(CreateOutputStream());
+ ASSERT_NO_FATAL_FAILURE(CreateInputStream());
+ ASSERT_NO_FATAL_FAILURE(streamOut->StartWorkerToSendBurstCommands());
+ // Read the head of the pipe and check that it starts with the first output burst, that is,
+ // the contents of the very first write has not been superseded due to pipe overflow.
+ // The burstCount is '0' because the very first burst is used to exit from the 'IDLE' state,
+ // see 'makeBurstCommands'.
+ ASSERT_NO_FATAL_FAILURE(streamIn->SendBurstCommands(false /*callPrepareToCloseBeforeJoin*/, 0,
+ true /*standbyInputWhenDone*/));
+ EXPECT_EQ(1, streamIn->getLastBurstIteration());
+ ASSERT_NO_FATAL_FAILURE(
+ streamOut->JoinWorkerAfterBurstCommands(true /*callPrepareToCloseBeforeJoin*/));
}
TEST_P(AudioModuleRemoteSubmix, OutputAndInput) {
- WithRemoteSubmix<IStreamOut> streamOut;
- ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
- ASSERT_EQ("", streamOut.skipTestReason());
- auto address = streamOut.getAudioDeviceAddress();
- ASSERT_TRUE(address.has_value());
-
- WithRemoteSubmix<IStreamIn> streamIn(address.value());
- ASSERT_NO_FATAL_FAILURE(streamIn.SetUp(module.get(), moduleConfig.get()));
- ASSERT_EQ("", streamIn.skipTestReason());
-
+ ASSERT_NO_FATAL_FAILURE(CreateOutputStream());
+ ASSERT_NO_FATAL_FAILURE(CreateInputStream());
// Start writing into the output stream.
- ASSERT_NO_FATAL_FAILURE(streamOut.StartWorkerToSendBurstCommands());
+ ASSERT_NO_FATAL_FAILURE(streamOut->StartWorkerToSendBurstCommands());
// Simultaneously, read from the input stream.
- ASSERT_NO_FATAL_FAILURE(streamIn.SendBurstCommands());
- ASSERT_NO_FATAL_FAILURE(streamOut.JoinWorkerAfterBurstCommands());
+ ASSERT_NO_FATAL_FAILURE(streamIn->SendBurstCommands(false /*callPrepareToCloseBeforeJoin*/));
+ ASSERT_NO_FATAL_FAILURE(
+ streamOut->JoinWorkerAfterBurstCommands(false /*callPrepareToCloseBeforeJoin*/));
}
TEST_P(AudioModuleRemoteSubmix, OpenInputMultipleTimes) {
- WithRemoteSubmix<IStreamOut> streamOut;
- ASSERT_NO_FATAL_FAILURE(streamOut.SetUp(module.get(), moduleConfig.get()));
- ASSERT_EQ("", streamOut.skipTestReason());
- auto address = streamOut.getAudioDeviceAddress();
- ASSERT_TRUE(address.has_value());
-
- const size_t streamInCount = 3;
- std::vector<std::unique_ptr<WithRemoteSubmix<IStreamIn>>> streamIns(streamInCount);
- for (size_t i = 0; i < streamInCount; i++) {
- streamIns[i] = std::make_unique<WithRemoteSubmix<IStreamIn>>(address.value());
- ASSERT_NO_FATAL_FAILURE(streamIns[i]->SetUp(module.get(), moduleConfig.get()));
+ ASSERT_NO_FATAL_FAILURE(CreateOutputStream());
+ ASSERT_NO_FATAL_FAILURE(CreateInputStream());
+ ASSERT_NO_FATAL_FAILURE(streamOut->StartWorkerToSendBurstCommands());
+ ASSERT_NO_FATAL_FAILURE(streamIn->SendBurstCommands(false /*callPrepareToCloseBeforeJoin*/, 1,
+ true /*standbyInputWhenDone*/));
+ // For the new stream, only create a new mix port config and a new patch.
+ const size_t extraStreamInCount = 2;
+ std::vector<std::unique_ptr<WithRemoteSubmix<IStreamIn>>> streamIns(extraStreamInCount);
+ for (size_t i = 0; i < extraStreamInCount; i++) {
+ streamIns[i] = std::make_unique<WithRemoteSubmix<IStreamIn>>();
+ ASSERT_NO_FATAL_FAILURE(streamIns[i]->SetUp(module.get(), moduleConfig.get(),
+ streamIn->getPortConfig(),
+ streamIn->getDevicePortConfig()));
ASSERT_EQ("", streamIns[i]->skipTestReason());
+ const auto inAddress = streamIns[i]->getAudioDeviceAddress();
+ ASSERT_TRUE(inAddress.has_value());
+ ASSERT_EQ(streamOut->getAudioDeviceAddress().value(), inAddress.value());
+ ASSERT_NO_FATAL_FAILURE(streamIns[i]->SendBurstCommands(
+ false /*callPrepareToCloseBeforeJoin*/, 1, true /*standbyInputWhenDone*/));
}
- // Start writing into the output stream.
- ASSERT_NO_FATAL_FAILURE(streamOut.StartWorkerToSendBurstCommands());
- // Simultaneously, read from input streams.
- for (size_t i = 0; i < streamInCount; i++) {
- ASSERT_NO_FATAL_FAILURE(streamIns[i]->StartWorkerToSendBurstCommands());
- }
- for (size_t i = 0; i < streamInCount; i++) {
- ASSERT_NO_FATAL_FAILURE(streamIns[i]->JoinWorkerAfterBurstCommands());
- }
- ASSERT_NO_FATAL_FAILURE(streamOut.JoinWorkerAfterBurstCommands());
- // Clean up input streams in the reverse order because the device connection is owned
- // by the first one.
- for (size_t i = streamInCount; i != 0; --i) {
- streamIns[i - 1].reset();
- }
+ ASSERT_NO_FATAL_FAILURE(
+ streamOut->JoinWorkerAfterBurstCommands(false /*callPrepareToCloseBeforeJoin*/));
}
INSTANTIATE_TEST_SUITE_P(AudioModuleRemoteSubmixTest, AudioModuleRemoteSubmix,
diff --git a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioAccessFamily.aidl b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioAccessFamily.aidl
index 471916f..f44385a 100644
--- a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioAccessFamily.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioAccessFamily.aidl
@@ -80,5 +80,4 @@
*/
LTE_CA = (1 << android.hardware.radio.RadioTechnology.LTE_CA) /* 524288 */,
NR = (1 << android.hardware.radio.RadioTechnology.NR) /* 1048576 */,
- NB_IOT_NTN = (1 << android.hardware.radio.RadioTechnology.NB_IOT_NTN) /* 2097152 */,
}
diff --git a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnology.aidl b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnology.aidl
index 201e694..7aae601 100644
--- a/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnology.aidl
+++ b/radio/aidl/aidl_api/android.hardware.radio/current/android/hardware/radio/RadioTechnology.aidl
@@ -80,5 +80,4 @@
*/
LTE_CA,
NR,
- NB_IOT_NTN,
}
diff --git a/radio/aidl/android/hardware/radio/RadioAccessFamily.aidl b/radio/aidl/android/hardware/radio/RadioAccessFamily.aidl
index 8c10bb9..9588ed9 100644
--- a/radio/aidl/android/hardware/radio/RadioAccessFamily.aidl
+++ b/radio/aidl/android/hardware/radio/RadioAccessFamily.aidl
@@ -55,8 +55,4 @@
* 5G NR. This is only use in 5G Standalone mode.
*/
NR = 1 << RadioTechnology.NR,
- /**
- * 3GPP NB-IOT (Narrowband Internet of Things) over Non-Terrestrial-Networks technology.
- */
- NB_IOT_NTN = 1 << RadioTechnology.NB_IOT_NTN,
}
diff --git a/radio/aidl/android/hardware/radio/RadioTechnology.aidl b/radio/aidl/android/hardware/radio/RadioTechnology.aidl
index 843bfd0..de93a2b 100644
--- a/radio/aidl/android/hardware/radio/RadioTechnology.aidl
+++ b/radio/aidl/android/hardware/radio/RadioTechnology.aidl
@@ -62,8 +62,4 @@
* 5G NR. This is only used in 5G Standalone mode.
*/
NR,
- /**
- * 3GPP NB-IOT (Narrowband Internet of Things) over Non-Terrestrial-Networks technology.
- */
- NB_IOT_NTN,
}
diff --git a/wifi/aidl/vts/functional/wifi_chip_aidl_test.cpp b/wifi/aidl/vts/functional/wifi_chip_aidl_test.cpp
index b4cb030..4677952 100644
--- a/wifi/aidl/vts/functional/wifi_chip_aidl_test.cpp
+++ b/wifi/aidl/vts/functional/wifi_chip_aidl_test.cpp
@@ -38,6 +38,7 @@
using aidl::android::hardware::wifi::IWifiP2pIface;
using aidl::android::hardware::wifi::IWifiRttController;
using aidl::android::hardware::wifi::WifiBand;
+using aidl::android::hardware::wifi::WifiChipCapabilities;
using aidl::android::hardware::wifi::WifiDebugHostWakeReasonStats;
using aidl::android::hardware::wifi::WifiDebugRingBufferStatus;
using aidl::android::hardware::wifi::WifiDebugRingBufferVerboseLevel;
@@ -987,6 +988,29 @@
EXPECT_EQ(instances.size(), 2);
}
+/*
+ * GetWifiChipCapabilities
+ */
+TEST_P(WifiChipAidlTest, GetWifiChipCapabilities) {
+ WifiChipCapabilities chipCapabilities;
+ auto status = wifi_chip_->getWifiChipCapabilities(&chipCapabilities);
+ if (checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
+ GTEST_SKIP() << "getWifiChipCapabilities() is not supported by vendor.";
+ }
+ EXPECT_TRUE(status.isOk());
+}
+
+/*
+ * SetMloMode
+ */
+TEST_P(WifiChipAidlTest, SetMloMode) {
+ auto status = wifi_chip_->setMloMode(IWifiChip::ChipMloMode::LOW_LATENCY);
+ if (checkStatusCode(&status, WifiStatusCode::ERROR_NOT_SUPPORTED)) {
+ GTEST_SKIP() << "setMloMode() is not supported by vendor.";
+ }
+ EXPECT_TRUE(status.isOk());
+}
+
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(WifiChipAidlTest);
INSTANTIATE_TEST_SUITE_P(WifiTest, WifiChipAidlTest,
testing::ValuesIn(android::getAidlHalInstanceNames(IWifi::descriptor)),
diff --git a/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp b/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp
index 590c58b..6723b1f 100644
--- a/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp
+++ b/wifi/hostapd/aidl/vts/functional/VtsHalHostapdTargetTest.cpp
@@ -86,6 +86,8 @@
isBridgedSupport = testing::checkSubstringInCommandOutput(
"/system/bin/cmd wifi get-softap-supported-features",
"wifi_softap_bridged_ap_supported");
+ isMloSupport = testing::checkSubstringInCommandOutput(
+ "/system/bin/cmd wifi get-softap-supported-features", "wifi_softap_mlo_supported");
}
virtual void TearDown() override {
@@ -100,6 +102,7 @@
bool isAcsSupport;
bool isWpa3SaeSupport;
bool isBridgedSupport;
+ bool isMloSupport;
int interface_version_;
IfaceParams getIfaceParamsWithoutAcs(std::string iface_name) {
@@ -476,6 +479,34 @@
EXPECT_TRUE(status.isOk());
}
+/**
+ * AddAccessPointWithMloConfig and remove link should pass
+ */
+TEST_P(HostapdAidl, AddAccessPointWithMloConfigAndRemoveInstance) {
+ if (interface_version_ < 3) {
+ GTEST_SKIP() << "MLO SAP is available in IfaceParams as of Hostapd V3";
+ }
+ if (!isMloSupport) GTEST_SKIP() << "Missing MLO AP support";
+ std::shared_ptr<IWifiApIface> wifi_ap_iface = HostapdAidlTestUtils::setupMloApIface();
+ EXPECT_TRUE(wifi_ap_iface.get() != nullptr);
+ std::string br_name;
+ std::vector<std::string> instances;
+ bool uses_mlo;
+ EXPECT_TRUE(wifi_ap_iface->getName(&br_name).isOk());
+ EXPECT_TRUE(wifi_ap_iface->getBridgedInstances(&instances).isOk());
+ EXPECT_TRUE(wifi_ap_iface->usesMlo(&uses_mlo).isOk());
+ EXPECT_TRUE(uses_mlo);
+
+ IfaceParams iface_params = getIfaceParamsWithBridgedModeACS(br_name);
+ iface_params.instanceIdentities = {instances[0], instances[1]};
+ iface_params.usesMlo = uses_mlo;
+ iface_params.hwModeParams.enable80211AX = true;
+ iface_params.hwModeParams.enable80211BE = true;
+
+ EXPECT_TRUE(hostapd->addAccessPoint(iface_params, getSaeNwParams()).isOk());
+ EXPECT_TRUE(hostapd->removeLinkFromMultipleLinkBridgedApIface(br_name, instances[0]).isOk());
+}
+
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(HostapdAidl);
INSTANTIATE_TEST_SUITE_P(
Hostapd, HostapdAidl,
diff --git a/wifi/hostapd/aidl/vts/functional/hostapd_aidl_test_utils.h b/wifi/hostapd/aidl/vts/functional/hostapd_aidl_test_utils.h
index 93540b2..3876998 100644
--- a/wifi/hostapd/aidl/vts/functional/hostapd_aidl_test_utils.h
+++ b/wifi/hostapd/aidl/vts/functional/hostapd_aidl_test_utils.h
@@ -77,4 +77,11 @@
return ap_iface_name;
}
+std::shared_ptr<IWifiApIface> setupMloApIface() {
+ std::shared_ptr<IWifiChip> wifi_chip = getWifiChip(kWifiInstanceName);
+ EXPECT_TRUE(wifi_chip.get() != nullptr);
+ return getWifiApOrBridgedApIface(
+ wifi_chip, generateApIfaceParams(IfaceConcurrencyType::AP_BRIDGED, true, 0));
+}
+
} // namespace HostapdAidlTestUtils
diff --git a/wifi/supplicant/aidl/vts/functional/Android.bp b/wifi/supplicant/aidl/vts/functional/Android.bp
index f94eb46..95ff6cd 100644
--- a/wifi/supplicant/aidl/vts/functional/Android.bp
+++ b/wifi/supplicant/aidl/vts/functional/Android.bp
@@ -137,3 +137,41 @@
"vts",
],
}
+
+cc_test {
+ name: "VtsHalWifiSupplicantP2pNetworkTargetTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: ["supplicant_p2p_network_aidl_test.cpp"],
+ shared_libs: [
+ "libbinder",
+ "libbinder_ndk",
+ "libvndksupport",
+ ],
+ static_libs: [
+ "android.hardware.wifi@1.0",
+ "android.hardware.wifi@1.1",
+ "android.hardware.wifi@1.2",
+ "android.hardware.wifi@1.3",
+ "android.hardware.wifi@1.4",
+ "android.hardware.wifi@1.5",
+ "android.hardware.wifi.common-V2-ndk",
+ "android.hardware.wifi.supplicant@1.0",
+ "android.hardware.wifi.supplicant@1.1",
+ "android.hardware.wifi.supplicant-V4-ndk",
+ "libwifi-system",
+ "libwifi-system-iface",
+ "VtsHalWifiV1_0TargetTestUtil",
+ "VtsHalWifiV1_5TargetTestUtil",
+ "VtsHalWifiSupplicantV1_0TargetTestUtil",
+ "android.hardware.wifi.common-V2-ndk",
+ "android.hardware.wifi-V3-ndk",
+ "VtsHalWifiTargetTestUtil",
+ ],
+ test_suites: [
+ "general-tests",
+ "vts",
+ ],
+}
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp
index 3638ac5..778e20a 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_p2p_iface_aidl_test.cpp
@@ -38,6 +38,7 @@
using aidl::android::hardware::wifi::supplicant::IfaceType;
using aidl::android::hardware::wifi::supplicant::ISupplicant;
using aidl::android::hardware::wifi::supplicant::ISupplicantP2pIface;
+using aidl::android::hardware::wifi::supplicant::ISupplicantP2pNetwork;
using aidl::android::hardware::wifi::supplicant::MiracastMode;
using aidl::android::hardware::wifi::supplicant::P2pAddGroupConfigurationParams;
using aidl::android::hardware::wifi::supplicant::P2pConnectInfo;
@@ -398,8 +399,8 @@
* SetWpsModelNumber
*/
TEST_P(SupplicantP2pIfaceAidlTest, SetWpsModelNumber) {
- const std::string modelNumber = "TestModelNumber";
- EXPECT_TRUE(p2p_iface_->setWpsModelName(modelNumber).isOk());
+ const std::string modelNumber = "Model1234";
+ EXPECT_TRUE(p2p_iface_->setWpsModelNumber(modelNumber).isOk());
}
/*
@@ -981,6 +982,96 @@
EXPECT_TRUE(p2p_iface_->reinvokePersistentGroup(params).isOk());
}
+/*
+ * Test the P2P network management functions.
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, ManageNetworks) {
+ std::shared_ptr<ISupplicantP2pNetwork> network;
+ EXPECT_TRUE(p2p_iface_->addNetwork(&network).isOk());
+ ASSERT_NE(network, nullptr);
+
+ std::vector<int32_t> networkList;
+ EXPECT_TRUE(p2p_iface_->listNetworks(&networkList).isOk());
+ ASSERT_FALSE(networkList.empty());
+
+ int networkId = networkList[0];
+ EXPECT_TRUE(p2p_iface_->getNetwork(networkId, &network).isOk());
+ ASSERT_NE(network, nullptr);
+ EXPECT_TRUE(p2p_iface_->removeNetwork(networkId).isOk());
+}
+
+/*
+ * Request and cancel service discovery
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, RequestAndCancelServiceDiscovery) {
+ int64_t discoveryId;
+ std::vector<uint8_t> query = {0x11, 0x22, 0x33};
+ EXPECT_TRUE(p2p_iface_->requestServiceDiscovery(kTestMacAddr, query, &discoveryId).isOk());
+ EXPECT_TRUE(p2p_iface_->cancelServiceDiscovery(discoveryId).isOk());
+}
+
+/*
+ * Start and stop WPS
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, StartAndStopWps) {
+ // Expected to fail with test values
+ std::string generatedPin;
+ EXPECT_FALSE(p2p_iface_->startWpsPbc(kTestGroupIfName, kTestMacAddr).isOk());
+ EXPECT_FALSE(
+ p2p_iface_->startWpsPinDisplay(kTestGroupIfName, kTestMacAddr, &generatedPin).isOk());
+ EXPECT_FALSE(p2p_iface_->startWpsPinKeypad(kTestGroupIfName, kTestConnectPin).isOk());
+ EXPECT_FALSE(p2p_iface_->cancelWps(kTestGroupIfName).isOk());
+}
+
+/*
+ * Create message and report handover for NFC Request
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, CreateAndReportNfcRequest) {
+ std::vector<uint8_t> requestMsg;
+ EXPECT_TRUE(p2p_iface_->createNfcHandoverRequestMessage(&requestMsg).isOk());
+ EXPECT_FALSE(requestMsg.empty());
+ EXPECT_TRUE(p2p_iface_->reportNfcHandoverResponse(requestMsg).isOk());
+}
+
+/*
+ * Create message and report handover for NFC Select
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, CreateAndReportNfcSelect) {
+ std::vector<uint8_t> selectMsg;
+ EXPECT_TRUE(p2p_iface_->createNfcHandoverSelectMessage(&selectMsg).isOk());
+ EXPECT_FALSE(selectMsg.empty());
+ EXPECT_TRUE(p2p_iface_->reportNfcHandoverInitiation(selectMsg).isOk());
+}
+
+/*
+ * RemoveClient
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, RemoveClient) {
+ // Method returns success for any valid MAC address
+ EXPECT_TRUE(p2p_iface_->removeClient(kTestMacAddr, false).isOk());
+ // Returns failure for any invalid MAC address
+ std::vector<uint8_t> invalidMacAddr = {0x11, 0x22};
+ EXPECT_FALSE(p2p_iface_->removeClient(invalidMacAddr, false).isOk());
+}
+
+/*
+ * ConfigureEapolIpAddressAllocationParams
+ */
+TEST_P(SupplicantP2pIfaceAidlTest, ConfigureEapolIpAddressAllocationParams) {
+ if (interface_version_ < 2) {
+ GTEST_SKIP() << "ConfigureEapolIpAddressAllocationParams is available as of Supplicant V2";
+ }
+ // The IP addresses are IPV4 addresses and higher-order address bytes are in the
+ // lower-order int bytes (e.g. 192.168.1.1 is represented as 0x0101A8C0)
+ EXPECT_TRUE(p2p_iface_
+ ->configureEapolIpAddressAllocationParams(0x0101A8C0, 0x00FFFFFF,
+ 0x0501A8C0, 0x0801A8C0)
+ .isOk());
+
+ // Clear the configuration.
+ EXPECT_TRUE(p2p_iface_->configureEapolIpAddressAllocationParams(0, 0, 0, 0).isOk());
+}
+
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantP2pIfaceAidlTest);
INSTANTIATE_TEST_SUITE_P(Supplicant, SupplicantP2pIfaceAidlTest,
testing::ValuesIn(android::getAidlHalInstanceNames(
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_p2p_network_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_p2p_network_aidl_test.cpp
new file mode 100644
index 0000000..c5a73f1
--- /dev/null
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_p2p_network_aidl_test.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2025 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 <VtsCoreUtil.h>
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/wifi/supplicant/BnSupplicant.h>
+#include <android/binder_manager.h>
+#include <android/binder_status.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <cutils/properties.h>
+
+#include "supplicant_test_utils.h"
+#include "wifi_aidl_test_utils.h"
+
+using aidl::android::hardware::wifi::supplicant::DebugLevel;
+using aidl::android::hardware::wifi::supplicant::IfaceType;
+using aidl::android::hardware::wifi::supplicant::ISupplicantP2pNetwork;
+using aidl::android::hardware::wifi::supplicant::MacAddress;
+using android::ProcessState;
+
+class SupplicantP2pNetworkAidlTest : public testing::TestWithParam<std::string> {
+ public:
+ void SetUp() override {
+ initializeService();
+ supplicant_ = getSupplicant(GetParam().c_str());
+ ASSERT_NE(supplicant_, nullptr);
+ ASSERT_TRUE(supplicant_->setDebugParams(DebugLevel::EXCESSIVE, true, true).isOk());
+
+ bool p2pEnabled = testing::deviceSupportsFeature("android.hardware.wifi.direct");
+ if (!p2pEnabled) {
+ GTEST_SKIP() << "Wi-Fi Direct is not supported, skip this test.";
+ }
+
+ EXPECT_TRUE(supplicant_->getP2pInterface(getP2pIfaceName(), &p2p_iface_).isOk());
+ ASSERT_NE(p2p_iface_, nullptr);
+ EXPECT_TRUE(p2p_iface_->addNetwork(&p2p_network_).isOk());
+ ASSERT_NE(p2p_network_, nullptr);
+ }
+
+ void TearDown() override {
+ stopSupplicantService();
+ startWifiFramework();
+ }
+
+ protected:
+ std::shared_ptr<ISupplicant> supplicant_;
+ std::shared_ptr<ISupplicantP2pIface> p2p_iface_;
+ std::shared_ptr<ISupplicantP2pNetwork> p2p_network_;
+};
+
+/*
+ * GetBssid
+ */
+TEST_P(SupplicantP2pNetworkAidlTest, GetBssid) {
+ std::vector<uint8_t> bssid;
+ EXPECT_TRUE(p2p_network_->getBssid(&bssid).isOk());
+}
+
+/*
+ * GetClientList
+ */
+TEST_P(SupplicantP2pNetworkAidlTest, GetClientList) {
+ // Expect failure if there are no clients
+ std::vector<MacAddress> clientList;
+ EXPECT_FALSE(p2p_network_->getClientList(&clientList).isOk());
+}
+
+/*
+ * GetId
+ */
+TEST_P(SupplicantP2pNetworkAidlTest, GetId) {
+ int networkId;
+ EXPECT_TRUE(p2p_network_->getId(&networkId).isOk());
+}
+
+/*
+ * GetInterfaceName
+ */
+TEST_P(SupplicantP2pNetworkAidlTest, GetInterfaceName) {
+ std::string expectedName = getP2pIfaceName();
+ std::string retrievedName;
+ EXPECT_TRUE(p2p_network_->getInterfaceName(&retrievedName).isOk());
+ EXPECT_EQ(retrievedName, expectedName);
+}
+
+/*
+ * GetSsid
+ */
+TEST_P(SupplicantP2pNetworkAidlTest, GetSsid) {
+ std::vector<uint8_t> ssid;
+ EXPECT_TRUE(p2p_network_->getSsid(&ssid).isOk());
+}
+
+/*
+ * GetType
+ */
+TEST_P(SupplicantP2pNetworkAidlTest, GetType) {
+ IfaceType ifaceType;
+ EXPECT_TRUE(p2p_network_->getType(&ifaceType).isOk());
+ EXPECT_EQ(ifaceType, IfaceType::P2P);
+}
+
+/*
+ * IsCurrent
+ */
+TEST_P(SupplicantP2pNetworkAidlTest, IsCurrent) {
+ bool isCurrent;
+ EXPECT_TRUE(p2p_network_->isCurrent(&isCurrent).isOk());
+ EXPECT_FALSE(isCurrent);
+}
+
+/*
+ * IsGroupOwner
+ */
+TEST_P(SupplicantP2pNetworkAidlTest, IsGroupOwner) {
+ bool isGroupOwner;
+ EXPECT_TRUE(p2p_network_->isGroupOwner(&isGroupOwner).isOk());
+ EXPECT_FALSE(isGroupOwner);
+}
+
+/*
+ * IsPersistent
+ */
+TEST_P(SupplicantP2pNetworkAidlTest, IsPersistent) {
+ bool isPersistent;
+ EXPECT_TRUE(p2p_network_->isPersistent(&isPersistent).isOk());
+ EXPECT_FALSE(isPersistent);
+}
+
+/*
+ * SetClientList
+ */
+TEST_P(SupplicantP2pNetworkAidlTest, SetClientList) {
+ MacAddress client = {{0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc}};
+ std::vector clientList = {client};
+ EXPECT_TRUE(p2p_network_->setClientList(clientList).isOk());
+}
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantP2pNetworkAidlTest);
+INSTANTIATE_TEST_SUITE_P(
+ Supplicant, SupplicantP2pNetworkAidlTest,
+ testing::ValuesIn(android::getAidlHalInstanceNames(ISupplicant::descriptor)),
+ android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ProcessState::self()->setThreadPoolMaxThreadCount(1);
+ ProcessState::self()->startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp
index 18b8ccb..cc3e821 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_sta_iface_aidl_test.cpp
@@ -47,8 +47,13 @@
using aidl::android::hardware::wifi::supplicant::QosCharacteristics;
using aidl::android::hardware::wifi::supplicant::QosPolicyScsData;
using aidl::android::hardware::wifi::supplicant::QosPolicyScsRequestStatus;
+using aidl::android::hardware::wifi::supplicant::SignalPollResult;
+using aidl::android::hardware::wifi::supplicant::UsdBaseConfig;
+using aidl::android::hardware::wifi::supplicant::UsdCapabilities;
using aidl::android::hardware::wifi::supplicant::UsdMessageInfo;
+using aidl::android::hardware::wifi::supplicant::UsdPublishConfig;
using aidl::android::hardware::wifi::supplicant::UsdServiceDiscoveryInfo;
+using aidl::android::hardware::wifi::supplicant::UsdSubscribeConfig;
using aidl::android::hardware::wifi::supplicant::UsdTerminateReasonCode;
using aidl::android::hardware::wifi::supplicant::WpaDriverCapabilitiesMask;
using aidl::android::hardware::wifi::supplicant::WpsConfigMethods;
@@ -880,6 +885,95 @@
EXPECT_EQ(1, responseList.size());
}
+/*
+ * Verify that all USD methods check the Service Specific Info (SSI) length
+ * and fail if the provided SSI is too long.
+ */
+TEST_P(SupplicantStaIfaceAidlTest, InvalidUsdServiceSpecificInfo) {
+ if (interface_version_ < 4) {
+ GTEST_SKIP() << "USD is available as of Supplicant V4";
+ }
+
+ UsdCapabilities caps;
+ EXPECT_TRUE(sta_iface_->getUsdCapabilities(&caps).isOk());
+ if (!caps.isUsdPublisherSupported && !caps.isUsdSubscriberSupported) {
+ GTEST_SKIP() << "USD publish and subscribe are not supported";
+ }
+
+ int commandId = 123;
+ std::vector<uint8_t> invalidSsi(caps.maxLocalSsiLengthBytes + 1);
+ UsdBaseConfig invalidBaseConfig;
+ invalidBaseConfig.serviceSpecificInfo = invalidSsi;
+
+ if (caps.isUsdPublisherSupported) {
+ UsdPublishConfig publishConfig;
+ publishConfig.usdBaseConfig = invalidBaseConfig;
+ EXPECT_FALSE(sta_iface_->startUsdPublish(commandId, publishConfig).isOk());
+ EXPECT_FALSE(sta_iface_->updateUsdPublish(commandId, invalidSsi).isOk());
+ }
+
+ if (caps.isUsdSubscriberSupported) {
+ UsdSubscribeConfig subscribeConfig;
+ subscribeConfig.usdBaseConfig = invalidBaseConfig;
+ EXPECT_FALSE(sta_iface_->startUsdSubscribe(commandId, subscribeConfig).isOk());
+ }
+
+ UsdMessageInfo messageInfo;
+ messageInfo.message = invalidSsi;
+ EXPECT_FALSE(sta_iface_->sendUsdMessage(messageInfo).isOk());
+}
+
+/*
+ * Cancel a USD Publish and Subscribe session.
+ */
+TEST_P(SupplicantStaIfaceAidlTest, CancelUsdSession) {
+ if (interface_version_ < 4) {
+ GTEST_SKIP() << "USD is available as of Supplicant V4";
+ }
+
+ UsdCapabilities caps;
+ EXPECT_TRUE(sta_iface_->getUsdCapabilities(&caps).isOk());
+ if (!caps.isUsdPublisherSupported && !caps.isUsdSubscriberSupported) {
+ GTEST_SKIP() << "USD publish and subscribe are not supported";
+ }
+
+ int sessionId = 123;
+ if (caps.isUsdPublisherSupported) {
+ // Method is expected to succeed, even if the session does not exist.
+ EXPECT_TRUE(sta_iface_->cancelUsdPublish(sessionId).isOk());
+ }
+ if (caps.isUsdSubscriberSupported) {
+ EXPECT_TRUE(sta_iface_->cancelUsdSubscribe(sessionId).isOk());
+ }
+}
+
+/*
+ * GenerateSelfDppConfiguration
+ */
+TEST_P(SupplicantStaIfaceAidlTest, GenerateSelfDppConfiguration) {
+ if (!keyMgmtSupported(sta_iface_, KeyMgmtMask::DPP)) {
+ GTEST_SKIP() << "Missing DPP support";
+ }
+ const std::string ssid = "my_test_ssid";
+ const std::vector<uint8_t> eckey_in = {0x2, 0x3, 0x4};
+
+ // Expect to fail as this test requires a DPP AKM supported AP and a valid private EC
+ // key generated by wpa_supplicant.
+ EXPECT_FALSE(sta_iface_->generateSelfDppConfiguration(ssid, eckey_in).isOk());
+}
+
+/*
+ * getSignalPollResults
+ */
+TEST_P(SupplicantStaIfaceAidlTest, GetSignalPollResults) {
+ if (interface_version_ < 2) {
+ GTEST_SKIP() << "getSignalPollResults is available as of Supplicant V2";
+ }
+
+ std::vector<SignalPollResult> results;
+ EXPECT_TRUE(sta_iface_->getSignalPollResults(&results).isOk());
+}
+
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantStaIfaceAidlTest);
INSTANTIATE_TEST_SUITE_P(Supplicant, SupplicantStaIfaceAidlTest,
testing::ValuesIn(android::getAidlHalInstanceNames(
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
index 9bdd2f5..5e6069f 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
@@ -32,6 +32,7 @@
using aidl::android::hardware::wifi::supplicant::AuthAlgMask;
using aidl::android::hardware::wifi::supplicant::BnSupplicantStaNetworkCallback;
using aidl::android::hardware::wifi::supplicant::DebugLevel;
+using aidl::android::hardware::wifi::supplicant::DppConnectionKeys;
using aidl::android::hardware::wifi::supplicant::EapMethod;
using aidl::android::hardware::wifi::supplicant::EapPhase2Method;
using aidl::android::hardware::wifi::supplicant::GroupCipherMask;
@@ -837,6 +838,21 @@
}
/*
+ * SetDppKeys
+ */
+TEST_P(SupplicantStaNetworkAidlTest, SetDppKeys) {
+ if (!keyMgmtSupported(sta_iface_, KeyMgmtMask::DPP)) {
+ GTEST_SKIP() << "Missing DPP support";
+ }
+
+ DppConnectionKeys in_keys;
+ in_keys.connector = std::vector<uint8_t>({0x11, 0x22, 0x33, 0x44});
+ in_keys.cSign = std::vector<uint8_t>({0x55, 0x66, 0x77, 0x88});
+ in_keys.netAccessKey = std::vector<uint8_t>({0xaa, 0xbb, 0xcc, 0xdd});
+ EXPECT_TRUE(sta_network_->setDppKeys(in_keys).isOk());
+}
+
+/*
* SetVendorData
*/
TEST_P(SupplicantStaNetworkAidlTest, SetVendorData) {