/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Nanache 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 #include #include #include #include #include #include #include #include #include #include #include "wifi_hidl_call_util.h" #include "wifi_hidl_test_utils.h" using namespace ::android::hardware::wifi::V1_0; using ::android::sp; using ::android::hardware::Return; using ::android::hardware::Void; using ::android::hardware::wifi::V1_0::IWifi; #define TIMEOUT_PERIOD 10 /** * Fixture to use for all NAN Iface HIDL interface tests. */ class WifiNanIfaceHidlTest : public ::testing::TestWithParam { public: virtual void SetUp() override { if (!::testing::deviceSupportsFeature("android.hardware.wifi.aware")) GTEST_SKIP() << "Skipping this test since NAN is not supported."; // Make sure test starts with a clean state stopWifi(GetInstanceName()); iwifiNanIface = getWifiNanIface(GetInstanceName()); ASSERT_NE(nullptr, iwifiNanIface.get()); ASSERT_EQ(WifiStatusCode::SUCCESS, HIDL_INVOKE(iwifiNanIface, registerEventCallback, new WifiNanIfaceEventCallback(*this)) .code); } virtual void TearDown() override { stopWifi(GetInstanceName()); } /* Used as a mechanism to inform the test about data/event callback */ inline void notify() { std::unique_lock lock(mtx_); count_++; cv_.notify_one(); } enum CallbackType { INVALID = -2, ANY_CALLBACK = -1, NOTIFY_CAPABILITIES_RESPONSE = 0, NOTIFY_ENABLE_RESPONSE, NOTIFY_CONFIG_RESPONSE, NOTIFY_DISABLE_RESPONSE, NOTIFY_START_PUBLISH_RESPONSE, NOTIFY_STOP_PUBLISH_RESPONSE, NOTIFY_START_SUBSCRIBE_RESPONSE, NOTIFY_STOP_SUBSCRIBE_RESPONSE, NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE, NOTIFY_CREATE_DATA_INTERFACE_RESPONSE, NOTIFY_DELETE_DATA_INTERFACE_RESPONSE, NOTIFY_INITIATE_DATA_PATH_RESPONSE, NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE, NOTIFY_TERMINATE_DATA_PATH_RESPONSE, EVENT_CLUSTER_EVENT, EVENT_DISABLED, EVENT_PUBLISH_TERMINATED, EVENT_SUBSCRIBE_TERMINATED, EVENT_MATCH, EVENT_MATCH_EXPIRED, EVENT_FOLLOWUP_RECEIVED, EVENT_TRANSMIT_FOLLOWUP, EVENT_DATA_PATH_REQUEST, EVENT_DATA_PATH_CONFIRM, EVENT_DATA_PATH_TERMINATED }; /* Test code calls this function to wait for data/event callback */ /* Must set callbackType = INVALID before call this function */ inline std::cv_status wait(CallbackType waitForCallbackType) { std::unique_lock lock(mtx_); EXPECT_NE(INVALID, waitForCallbackType); // can't ASSERT in a non-void-returning method std::cv_status status = std::cv_status::no_timeout; auto now = std::chrono::system_clock::now(); while (count_ == 0) { status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD)); if (status == std::cv_status::timeout) return status; if (waitForCallbackType != ANY_CALLBACK && callbackType != INVALID && callbackType != waitForCallbackType) { count_--; } } count_--; return status; } class WifiNanIfaceEventCallback: public IWifiNanIfaceEventCallback { WifiNanIfaceHidlTest& parent_; public: WifiNanIfaceEventCallback(WifiNanIfaceHidlTest& parent) : parent_(parent) {}; virtual ~WifiNanIfaceEventCallback() = default; Return notifyCapabilitiesResponse( uint16_t id, const WifiNanStatus& status, const NanCapabilities& capabilities) override { parent_.callbackType = NOTIFY_CAPABILITIES_RESPONSE; parent_.id = id; parent_.status = status; parent_.capabilities = capabilities; parent_.notify(); return Void(); } Return notifyEnableResponse( uint16_t id, const WifiNanStatus& status) override { parent_.callbackType = NOTIFY_ENABLE_RESPONSE; parent_.id = id; parent_.status = status; parent_.notify(); return Void(); } Return notifyConfigResponse( uint16_t id, const WifiNanStatus& status) override { parent_.callbackType = NOTIFY_CONFIG_RESPONSE; parent_.id = id; parent_.status = status; parent_.notify(); return Void(); } Return notifyDisableResponse( uint16_t id, const WifiNanStatus& status) override { parent_.callbackType = NOTIFY_DISABLE_RESPONSE; parent_.id = id; parent_.status = status; parent_.notify(); return Void(); } Return notifyStartPublishResponse( uint16_t id, const WifiNanStatus& status, uint8_t sessionId) override { parent_.callbackType = NOTIFY_START_PUBLISH_RESPONSE; parent_.id = id; parent_.status = status; parent_.sessionId = sessionId; parent_.notify(); return Void(); } Return notifyStopPublishResponse( uint16_t id, const WifiNanStatus& status) override { parent_.callbackType = NOTIFY_STOP_PUBLISH_RESPONSE; parent_.id = id; parent_.status = status; parent_.notify(); return Void(); } Return notifyStartSubscribeResponse( uint16_t id, const WifiNanStatus& status, uint8_t sessionId) override { parent_.callbackType = NOTIFY_START_SUBSCRIBE_RESPONSE; parent_.id = id; parent_.status = status; parent_.sessionId = sessionId; parent_.notify(); return Void(); } Return notifyStopSubscribeResponse( uint16_t id, const WifiNanStatus& status) override { parent_.callbackType = NOTIFY_STOP_SUBSCRIBE_RESPONSE; parent_.id = id; parent_.status = status; parent_.notify(); return Void(); } Return notifyTransmitFollowupResponse( uint16_t id, const WifiNanStatus& status) override { parent_.callbackType = NOTIFY_TRANSMIT_FOLLOWUP_RESPONSE; parent_.id = id; parent_.status = status; parent_.notify(); return Void(); } Return notifyCreateDataInterfaceResponse( uint16_t id, const WifiNanStatus& status) override { parent_.callbackType = NOTIFY_CREATE_DATA_INTERFACE_RESPONSE; parent_.id = id; parent_.status = status; parent_.notify(); return Void(); } Return notifyDeleteDataInterfaceResponse( uint16_t id, const WifiNanStatus& status) override { parent_.callbackType = NOTIFY_DELETE_DATA_INTERFACE_RESPONSE; parent_.id = id; parent_.status = status; parent_.notify(); return Void(); } Return notifyInitiateDataPathResponse( uint16_t id, const WifiNanStatus& status, uint32_t ndpInstanceId) override { parent_.callbackType = NOTIFY_INITIATE_DATA_PATH_RESPONSE; parent_.id = id; parent_.status = status; parent_.ndpInstanceId = ndpInstanceId; parent_.notify(); return Void(); } Return notifyRespondToDataPathIndicationResponse( uint16_t id, const WifiNanStatus& status) override { parent_.callbackType = NOTIFY_RESPOND_TO_DATA_PATH_INDICATION_RESPONSE; parent_.id = id; parent_.status = status; parent_.notify(); return Void(); } Return notifyTerminateDataPathResponse( uint16_t id, const WifiNanStatus& status) override { parent_.callbackType = NOTIFY_TERMINATE_DATA_PATH_RESPONSE; parent_.id = id; parent_.status = status; parent_.notify(); return Void(); } Return eventClusterEvent( const NanClusterEventInd& event) override { parent_.callbackType = EVENT_CLUSTER_EVENT; parent_.nanClusterEventInd = event; parent_.notify(); return Void(); } Return eventDisabled( const WifiNanStatus& status) override { parent_.callbackType = EVENT_DISABLED; parent_.status = status; parent_.notify(); return Void(); } Return eventPublishTerminated( uint8_t sessionId, const WifiNanStatus& status) override { parent_.callbackType = EVENT_PUBLISH_TERMINATED; parent_.sessionId = sessionId; parent_.status = status; parent_.notify(); return Void(); } Return eventSubscribeTerminated( uint8_t sessionId, const WifiNanStatus& status) override { parent_.callbackType = EVENT_SUBSCRIBE_TERMINATED; parent_.sessionId = sessionId; parent_.status = status; parent_.notify(); return Void(); } Return eventMatch( const NanMatchInd& event) override { parent_.callbackType = EVENT_MATCH; parent_.nanMatchInd = event; parent_.notify(); return Void(); } Return eventMatchExpired( uint8_t discoverySessionId, uint32_t peerId) override { parent_.callbackType = EVENT_MATCH_EXPIRED; parent_.sessionId = discoverySessionId; parent_.peerId = peerId; parent_.notify(); return Void(); } Return eventFollowupReceived( const NanFollowupReceivedInd& event) override { parent_.callbackType = EVENT_FOLLOWUP_RECEIVED; parent_.nanFollowupReceivedInd = event; parent_.notify(); return Void(); } Return eventTransmitFollowup( uint16_t id, const WifiNanStatus& status) override { parent_.callbackType = EVENT_TRANSMIT_FOLLOWUP; parent_.id = id; parent_.status = status; parent_.notify(); return Void(); } Return eventDataPathRequest( const NanDataPathRequestInd& event) override { parent_.callbackType = EVENT_DATA_PATH_REQUEST; parent_.nanDataPathRequestInd = event; parent_.notify(); return Void(); } Return eventDataPathConfirm( const NanDataPathConfirmInd& event) override { parent_.callbackType = EVENT_DATA_PATH_CONFIRM; parent_.nanDataPathConfirmInd = event; parent_.notify(); return Void(); } Return eventDataPathTerminated( uint32_t ndpInstanceId) override { parent_.callbackType = EVENT_DATA_PATH_TERMINATED; parent_.ndpInstanceId = ndpInstanceId; parent_.notify(); return Void(); } }; private: // synchronization objects std::mutex mtx_; std::condition_variable cv_; int count_; protected: android::sp iwifiNanIface; // Data from IWifiNanIfaceEventCallback callbacks: this is the collection of all // arguments to all callbacks. They are set by the callback (notifications or // events) and can be retrieved by tests. CallbackType callbackType; uint16_t id; WifiNanStatus status; NanCapabilities capabilities; uint8_t sessionId; uint32_t ndpInstanceId; NanClusterEventInd nanClusterEventInd; NanMatchInd nanMatchInd; uint32_t peerId; NanFollowupReceivedInd nanFollowupReceivedInd; NanDataPathRequestInd nanDataPathRequestInd; NanDataPathConfirmInd nanDataPathConfirmInd; std::string GetInstanceName() { return GetParam(); } }; /* * Create: * Ensures that an instance of the IWifiNanIface proxy object is * successfully created. */ TEST_P(WifiNanIfaceHidlTest, Create) { // The creation of a proxy object is tested as part of SetUp method. } /* * Fail: use past destruction * Ensure that API calls fail with ERROR_WIFI_IFACE_INVALID when using an interface once wifi * is disabled. */ TEST_P(WifiNanIfaceHidlTest, FailOnIfaceInvalid) { stopWifi(GetInstanceName()); android::sp iwifiNanIface = getWifiNanIface(GetInstanceName()); ASSERT_NE(nullptr, iwifiNanIface.get()); stopWifi(GetInstanceName()); sleep(5); // make sure that all chips/interfaces are invalidated ASSERT_EQ(WifiStatusCode::ERROR_WIFI_IFACE_INVALID, HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, 0).code); } /* * getCapabilitiesRequest: validate that returns capabilities. */ TEST_P(WifiNanIfaceHidlTest, getCapabilitiesRequest) { uint16_t inputCmdId = 10; callbackType = INVALID; ASSERT_EQ( WifiStatusCode::SUCCESS, HIDL_INVOKE(iwifiNanIface, getCapabilitiesRequest, inputCmdId).code); // wait for a callback ASSERT_EQ(std::cv_status::no_timeout, wait(NOTIFY_CAPABILITIES_RESPONSE)); ASSERT_EQ(NOTIFY_CAPABILITIES_RESPONSE, callbackType); ASSERT_EQ(id, inputCmdId); // check for reasonable capability values EXPECT_GT(capabilities.maxConcurrentClusters, (unsigned int)0); EXPECT_GT(capabilities.maxPublishes, (unsigned int)0); EXPECT_GT(capabilities.maxSubscribes, (unsigned int)0); EXPECT_EQ(capabilities.maxServiceNameLen, (unsigned int)255); EXPECT_EQ(capabilities.maxMatchFilterLen, (unsigned int)255); EXPECT_GT(capabilities.maxTotalMatchFilterLen, (unsigned int)255); EXPECT_EQ(capabilities.maxServiceSpecificInfoLen, (unsigned int)255); EXPECT_GE(capabilities.maxExtendedServiceSpecificInfoLen, (unsigned int)255); EXPECT_GT(capabilities.maxNdiInterfaces, (unsigned int)0); EXPECT_GT(capabilities.maxNdpSessions, (unsigned int)0); EXPECT_GT(capabilities.maxAppInfoLen, (unsigned int)0); EXPECT_GT(capabilities.maxQueuedTransmitFollowupMsgs, (unsigned int)0); EXPECT_GT(capabilities.maxSubscribeInterfaceAddresses, (unsigned int)0); EXPECT_NE(capabilities.supportedCipherSuites, (unsigned int)0); } INSTANTIATE_TEST_SUITE_P( PerInstance, WifiNanIfaceHidlTest, testing::ValuesIn( android::hardware::getAllHalInstanceNames(IWifi::descriptor)), android::hardware::PrintInstanceNameToString);