/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "chre/pal/util/wifi_scan_cache.h" #include #include #include #include "chre/platform/log.h" #include "chre/platform/shared/pal_system_api.h" #include "chre/util/fixed_size_vector.h" #include "chre/util/macros.h" #include "chre/util/nanoapp/wifi.h" #include "chre/util/optional.h" #include "chre_api/chre/common.h" #include "gtest/gtest.h" namespace { /************************************************ * Prototypes ***********************************************/ void chreWifiScanResponseCallback(bool pending, uint8_t errorCode); void chreWifiScanEventCallback(struct chreWifiScanEvent *event); struct WifiScanResponse { bool pending; uint8_t errorCode; }; /************************************************ * Global variables ***********************************************/ const chrePalWifiCallbacks gChreWifiPalCallbacks = { .scanResponseCallback = chreWifiScanResponseCallback, .scanEventCallback = chreWifiScanEventCallback, }; chre::Optional gWifiScanResponse; chre::FixedSizeVector gWifiScanResultList; chre::Optional gExpectedWifiScanEvent; bool gWifiScanEventCompleted; /************************************************ * Test class ***********************************************/ class WifiScanCacheTests : public ::testing::Test { protected: void SetUp() override { clearTestState(); EXPECT_TRUE(chreWifiScanCacheInit(&chre::gChrePalSystemApi, &gChreWifiPalCallbacks)); } void TearDown() override { chreWifiScanCacheDeinit(); } void clearTestState() { gExpectedWifiScanEvent.reset(); gWifiScanResponse.reset(); while (!gWifiScanResultList.empty()) { gWifiScanResultList.pop_back(); } } }; /************************************************ * Private functions ***********************************************/ void chreWifiScanResponseCallback(bool pending, uint8_t errorCode) { WifiScanResponse response = { .pending = pending, .errorCode = errorCode, }; gWifiScanResponse = response; } void chreWifiScanEventCallback(struct chreWifiScanEvent *event) { ASSERT_TRUE(gExpectedWifiScanEvent.has_value()); EXPECT_EQ(event->version, gExpectedWifiScanEvent->version); EXPECT_EQ(event->scanType, gExpectedWifiScanEvent->scanType); EXPECT_EQ(event->ssidSetSize, gExpectedWifiScanEvent->ssidSetSize); ASSERT_EQ(event->scannedFreqListLen, gExpectedWifiScanEvent->scannedFreqListLen); if (event->scannedFreqListLen > 0) { ASSERT_NE(event->scannedFreqList, nullptr); EXPECT_EQ( memcmp(gExpectedWifiScanEvent->scannedFreqList, event->scannedFreqList, event->scannedFreqListLen * sizeof(uint32_t)), 0); } EXPECT_EQ(event->radioChainPref, gExpectedWifiScanEvent->radioChainPref); EXPECT_EQ(event->eventIndex, gExpectedWifiScanEvent->eventIndex); gExpectedWifiScanEvent->eventIndex++; for (uint8_t i = 0; i < event->resultCount; i++) { const chreWifiScanResult &result = event->results[i]; gWifiScanResultList.push_back(result); } if (gWifiScanResultList.size() == event->resultTotal) { gWifiScanEventCompleted = true; } chreWifiScanCacheReleaseScanEvent(event); } void beginDefaultWifiCache(const uint32_t *scannedFreqList, uint16_t scannedFreqListLen, bool activeScanResult = true) { chreWifiScanEvent event; memset(&event, 0, sizeof(chreWifiScanEvent)); event.version = CHRE_WIFI_SCAN_EVENT_VERSION; event.scanType = CHRE_WIFI_SCAN_TYPE_ACTIVE; event.scannedFreqList = scannedFreqList; event.scannedFreqListLen = scannedFreqListLen; event.radioChainPref = CHRE_WIFI_RADIO_CHAIN_PREF_DEFAULT; gExpectedWifiScanEvent = event; chreWifiScanCacheScanEventBegin( static_cast(gExpectedWifiScanEvent->scanType), gExpectedWifiScanEvent->ssidSetSize, gExpectedWifiScanEvent->scannedFreqList, gExpectedWifiScanEvent->scannedFreqListLen, gExpectedWifiScanEvent->radioChainPref, activeScanResult); } void cacheDefaultWifiCacheTest(size_t numEvents, const uint32_t *scannedFreqList, uint16_t scannedFreqListLen, bool activeScanResult = true, bool scanMonitoringEnabled = false) { gWifiScanEventCompleted = false; beginDefaultWifiCache(scannedFreqList, scannedFreqListLen, activeScanResult); chreWifiScanResult result = {}; for (size_t i = 0; i < numEvents; i++) { result.rssi = static_cast(i); memcpy(result.bssid, &i, sizeof(i)); chreWifiScanCacheScanEventAdd(&result); } chreWifiScanCacheScanEventEnd(CHRE_ERROR_NONE); if (activeScanResult) { EXPECT_TRUE(gWifiScanResponse.has_value()); EXPECT_EQ(gWifiScanResponse->pending, true); ASSERT_EQ(gWifiScanResponse->errorCode, CHRE_ERROR_NONE); } else { EXPECT_FALSE(gWifiScanResponse.has_value()); } size_t numEventsExpected = 0; if (activeScanResult || scanMonitoringEnabled) { numEventsExpected = std::min( numEvents, static_cast(CHRE_PAL_WIFI_SCAN_CACHE_CAPACITY)); ASSERT_TRUE(gWifiScanEventCompleted); } ASSERT_EQ(gWifiScanResultList.size(), numEventsExpected); for (size_t i = 0; i < gWifiScanResultList.size(); i++) { // ageMs is not known apriori result.ageMs = gWifiScanResultList[i].ageMs; result.rssi = static_cast(i); memcpy(result.bssid, &i, sizeof(i)); EXPECT_EQ( memcmp(&gWifiScanResultList[i], &result, sizeof(chreWifiScanResult)), 0); } } void testCacheDispatch(size_t numEvents, uint32_t maxScanAgeMs, bool expectSuccess) { cacheDefaultWifiCacheTest(numEvents, nullptr /* scannedFreqList */, 0 /* scannedFreqListLen */); gExpectedWifiScanEvent->eventIndex = 0; gWifiScanResponse.reset(); while (!gWifiScanResultList.empty()) { gWifiScanResultList.pop_back(); } struct chreWifiScanParams params = { .scanType = CHRE_WIFI_SCAN_TYPE_NO_PREFERENCE, .maxScanAgeMs = maxScanAgeMs, .frequencyListLen = 0, .frequencyList = nullptr, .ssidListLen = 0, .ssidList = nullptr, .radioChainPref = CHRE_WIFI_RADIO_CHAIN_PREF_DEFAULT, .channelSet = CHRE_WIFI_CHANNEL_SET_NON_DFS, }; EXPECT_EQ(chreWifiScanCacheDispatchFromCache(¶ms), expectSuccess); EXPECT_EQ(gWifiScanResponse.has_value(), expectSuccess); if (expectSuccess) { EXPECT_TRUE(gWifiScanResponse->pending); EXPECT_EQ(gWifiScanResponse->errorCode, CHRE_ERROR_NONE); } EXPECT_EQ(gWifiScanResultList.size(), expectSuccess ? numEvents : 0); } } // anonymous namespace /************************************************ * Tests ***********************************************/ TEST_F(WifiScanCacheTests, SingleWifiResultTest) { cacheDefaultWifiCacheTest(1 /* numEvents */, nullptr /* scannedFreqList */, 0 /* scannedFreqListLen */); } TEST_F(WifiScanCacheTests, MultiWifiResultTest) { cacheDefaultWifiCacheTest( CHRE_PAL_WIFI_SCAN_CACHE_MAX_RESULT_COUNT + 1 /* numEvents */, nullptr /* scannedFreqList */, 0 /* scannedFreqListLen */); } TEST_F(WifiScanCacheTests, WifiResultOverflowTest) { cacheDefaultWifiCacheTest( CHRE_PAL_WIFI_SCAN_CACHE_CAPACITY + 1 /* numEvents */, nullptr /* scannedFreqList */, 0 /* scannedFreqListLen */); } TEST_F(WifiScanCacheTests, EmptyWifiResultTest) { cacheDefaultWifiCacheTest(0 /* numEvents */, nullptr /* scannedFreqList */, 0 /* scannedFreqListLen */); } TEST_F(WifiScanCacheTests, FailedWifiCacheTest) { beginDefaultWifiCache(nullptr /* scannedFreqList */, 0 /* scannedFreqListLen */); chreWifiScanCacheScanEventEnd(CHRE_ERROR); EXPECT_TRUE(gWifiScanResponse.has_value()); EXPECT_FALSE(gWifiScanResponse->pending); EXPECT_EQ(gWifiScanResponse->errorCode, CHRE_ERROR); EXPECT_EQ(gWifiScanResultList.size(), 0); } TEST_F(WifiScanCacheTests, FrequencyListTest) { const uint32_t freqList[2] = {5210, 5240}; cacheDefaultWifiCacheTest(1 /* numEvents */, freqList, ARRAY_SIZE(freqList)); } TEST_F(WifiScanCacheTests, InvalidFrequencyListTest) { beginDefaultWifiCache(nullptr /* scannedFreqList */, 1 /* scannedFreqListLen */); EXPECT_TRUE(gWifiScanResponse.has_value()); EXPECT_FALSE(gWifiScanResponse->pending); EXPECT_EQ(gWifiScanResponse->errorCode, CHRE_ERROR_INVALID_ARGUMENT); EXPECT_EQ(gWifiScanResultList.size(), 0); } TEST_F(WifiScanCacheTests, SequentialWifiResultTest) { cacheDefaultWifiCacheTest(1 /* numEvents */, nullptr /* scannedFreqList */, 0 /* scannedFreqListLen */); clearTestState(); cacheDefaultWifiCacheTest(1 /* numEvents */, nullptr /* scannedFreqList */, 0 /* scannedFreqListLen */); } TEST_F(WifiScanCacheTests, ScanMonitorDisabledTest) { cacheDefaultWifiCacheTest(1 /* numEvents */, nullptr /* scannedFreqList */, 0 /* scannedFreqListLen */, false /* activeScanResult */, false /* scanMonitoringEnabled */); } TEST_F(WifiScanCacheTests, ScanMonitorEnabledTest) { chreWifiScanCacheConfigureScanMonitor(true /* enable */); cacheDefaultWifiCacheTest(1 /* numEvents */, nullptr /* scannedFreqList */, 0 /* scannedFreqListLen */, false /* activeScanResult */, true /* scanMonitoringEnabled */); } TEST_F(WifiScanCacheTests, ScanMonitorEnableDisableTest) { chreWifiScanCacheConfigureScanMonitor(true /* enable */); cacheDefaultWifiCacheTest(1 /* numEvents */, nullptr /* scannedFreqList */, 0 /* scannedFreqListLen */, false /* activeScanResult */, true /* scanMonitoringEnabled */); clearTestState(); chreWifiScanCacheConfigureScanMonitor(false /* enable */); cacheDefaultWifiCacheTest(1 /* numEvents */, nullptr /* scannedFreqList */, 0 /* scannedFreqListLen */, false /* activeScanResult */, false /* scanMonitoringEnabled */); } TEST_F(WifiScanCacheTests, CacheDispatchTest) { testCacheDispatch(1 /* numEvents */, 5000 /* maxScanAgeMs */, true /* expectSuccess */); } TEST_F(WifiScanCacheTests, ZeroMaxScanAgeCacheDispatchTest) { testCacheDispatch(1 /* numEvents */, 0 /* maxScanAgeMs */, false /* expectSuccess */); } TEST_F(WifiScanCacheTests, DuplicateScanResultTest) { beginDefaultWifiCache(nullptr /* scannedFreqList */, 0 /* scannedFreqListLen */, true /* activeScanResult */); chreWifiScanResult result = {}; result.rssi = -98; result.primaryChannel = 5270; const char *dummySsid = "Test ssid"; memcpy(result.ssid, dummySsid, strlen(dummySsid)); result.ssidLen = strlen(dummySsid); const char *dummyBssid = "12:34:56:78:9a:bc"; memcpy(result.bssid, dummyBssid, strlen(dummyBssid)); chreWifiScanResult result2 = {}; result.rssi = -98; result.primaryChannel = 5270; const char *dummySsid2 = "Test ssid 2"; memcpy(result.ssid, dummySsid, strlen(dummySsid2)); result.ssidLen = strlen(dummySsid); const char *dummyBssid2 = "34:56:78:9a:bc:de"; memcpy(result.bssid, dummyBssid, strlen(dummyBssid2)); chreWifiScanCacheScanEventAdd(&result); chreWifiScanCacheScanEventAdd(&result2); chreWifiScanCacheScanEventAdd(&result); chreWifiScanCacheScanEventEnd(CHRE_ERROR_NONE); EXPECT_TRUE(gWifiScanResponse.has_value()); EXPECT_EQ(gWifiScanResponse->pending, true); ASSERT_EQ(gWifiScanResponse->errorCode, CHRE_ERROR_NONE); ASSERT_EQ(gWifiScanResultList.size(), 2); result.ageMs = gWifiScanResultList[0].ageMs; EXPECT_EQ( memcmp(&gWifiScanResultList[0], &result, sizeof(chreWifiScanResult)), 0); result2.ageMs = gWifiScanResultList[1].ageMs; EXPECT_EQ( memcmp(&gWifiScanResultList[1], &result2, sizeof(chreWifiScanResult)), 0); }