/* * Copyright (C) 2022 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 #include "chre/core/event_loop_manager.h" #include "chre/core/settings.h" #include "chre/platform/linux/pal_nan.h" #include "chre/platform/linux/pal_wifi.h" #include "chre/platform/log.h" #include "chre/util/system/napp_permissions.h" #include "chre_api/chre/event.h" #include "chre_api/chre/wifi.h" #include "gtest/gtest.h" #include "test_base.h" #include "test_event.h" #include "test_event_queue.h" #include "test_util.h" namespace chre { namespace { CREATE_CHRE_TEST_EVENT(SCAN_REQUEST, 20); struct WifiAsyncData { const uint32_t *cookie; chreError errorCode; }; class WifiScanRequestQueueTestBase : public TestBase { public: void SetUp() { TestBase::SetUp(); // Add delay to make sure the requests are queued. chrePalWifiDelayResponse(PalWifiAsyncRequestTypes::SCAN, std::chrono::seconds(1)); } void TearDown() { TestBase::TearDown(); chrePalWifiDelayResponse(PalWifiAsyncRequestTypes::SCAN, std::chrono::seconds(0)); } }; struct WifiScanTestNanoapp : public TestNanoapp { uint32_t perms = NanoappPermissions::CHRE_PERMS_WIFI; decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType, const void *eventData) { constexpr uint8_t kMaxPendingCookie = 10; static uint32_t cookies[kMaxPendingCookie]; static uint8_t nextFreeCookieIndex = 0; switch (eventType) { case CHRE_EVENT_WIFI_ASYNC_RESULT: { auto *event = static_cast(eventData); TestEventQueueSingleton::get()->pushEvent( CHRE_EVENT_WIFI_ASYNC_RESULT, WifiAsyncData{ .cookie = static_cast(event->cookie), .errorCode = static_cast(event->errorCode)}); break; } case CHRE_EVENT_WIFI_SCAN_RESULT: { TestEventQueueSingleton::get()->pushEvent(CHRE_EVENT_WIFI_SCAN_RESULT); break; } case CHRE_EVENT_TEST_EVENT: { auto event = static_cast(eventData); switch (event->type) { case SCAN_REQUEST: bool success = false; if (nextFreeCookieIndex < kMaxPendingCookie) { cookies[nextFreeCookieIndex] = *static_cast(event->data); success = chreWifiRequestScanAsyncDefault( &cookies[nextFreeCookieIndex]); nextFreeCookieIndex++; } else { LOGE("Too many cookies passed from test body!"); } TestEventQueueSingleton::get()->pushEvent(SCAN_REQUEST, success); } } } }; }; TEST_F(TestBase, WifiScanBasicSettingTest) { auto app = loadNanoapp(); EventLoopManagerSingleton::get()->getSettingManager().postSettingChange( Setting::WIFI_AVAILABLE, true /* enabled */); constexpr uint32_t firstCookie = 0x1010; bool success; WifiAsyncData wifiAsyncData; sendEventToNanoapp(app, SCAN_REQUEST, firstCookie); waitForEvent(SCAN_REQUEST, &success); EXPECT_TRUE(success); waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT, &wifiAsyncData); EXPECT_EQ(wifiAsyncData.errorCode, CHRE_ERROR_NONE); EXPECT_EQ(*wifiAsyncData.cookie, firstCookie); waitForEvent(CHRE_EVENT_WIFI_SCAN_RESULT); EventLoopManagerSingleton::get()->getSettingManager().postSettingChange( Setting::WIFI_AVAILABLE, false /* enabled */); constexpr uint32_t secondCookie = 0x2020; sendEventToNanoapp(app, SCAN_REQUEST, secondCookie); waitForEvent(SCAN_REQUEST, &success); EXPECT_TRUE(success); waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT, &wifiAsyncData); EXPECT_EQ(wifiAsyncData.errorCode, CHRE_ERROR_FUNCTION_DISABLED); EXPECT_EQ(*wifiAsyncData.cookie, secondCookie); EventLoopManagerSingleton::get()->getSettingManager().postSettingChange( Setting::WIFI_AVAILABLE, true /* enabled */); unloadNanoapp(app); } TEST_F(WifiScanRequestQueueTestBase, WifiQueuedScanSettingChangeTest) { struct WifiScanTestNanoappTwo : public WifiScanTestNanoapp { uint64_t id = 0x1123456789abcdef; }; auto firstApp = loadNanoapp(); auto secondApp = loadNanoapp(); constexpr uint32_t firstRequestCookie = 0x1010; constexpr uint32_t secondRequestCookie = 0x2020; bool success; sendEventToNanoapp(firstApp, SCAN_REQUEST, firstRequestCookie); waitForEvent(SCAN_REQUEST, &success); EXPECT_TRUE(success); sendEventToNanoapp(secondApp, SCAN_REQUEST, secondRequestCookie); waitForEvent(SCAN_REQUEST, &success); EXPECT_TRUE(success); EventLoopManagerSingleton::get()->getSettingManager().postSettingChange( Setting::WIFI_AVAILABLE, false /* enabled */); WifiAsyncData wifiAsyncData; waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT, &wifiAsyncData); EXPECT_EQ(wifiAsyncData.errorCode, CHRE_ERROR_NONE); EXPECT_EQ(*wifiAsyncData.cookie, firstRequestCookie); waitForEvent(CHRE_EVENT_WIFI_SCAN_RESULT); waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT, &wifiAsyncData); EXPECT_EQ(wifiAsyncData.errorCode, CHRE_ERROR_FUNCTION_DISABLED); EXPECT_EQ(*wifiAsyncData.cookie, secondRequestCookie); EventLoopManagerSingleton::get()->getSettingManager().postSettingChange( Setting::WIFI_AVAILABLE, true /* enabled */); unloadNanoapp(firstApp); unloadNanoapp(secondApp); } TEST_F(WifiScanRequestQueueTestBase, WifiScanRejectRequestFromSameNanoapp) { auto app = loadNanoapp(); constexpr uint32_t firstRequestCookie = 0x1010; constexpr uint32_t secondRequestCookie = 0x2020; bool success; sendEventToNanoapp(app, SCAN_REQUEST, firstRequestCookie); waitForEvent(SCAN_REQUEST, &success); EXPECT_TRUE(success); sendEventToNanoapp(app, SCAN_REQUEST, secondRequestCookie); waitForEvent(SCAN_REQUEST, &success); EXPECT_FALSE(success); WifiAsyncData wifiAsyncData; waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT, &wifiAsyncData); EXPECT_EQ(wifiAsyncData.errorCode, CHRE_ERROR_NONE); EXPECT_EQ(*wifiAsyncData.cookie, firstRequestCookie); waitForEvent(CHRE_EVENT_WIFI_SCAN_RESULT); unloadNanoapp(app); } TEST_F(WifiScanRequestQueueTestBase, WifiScanActiveScanFromDistinctNanoapps) { CREATE_CHRE_TEST_EVENT(CONCURRENT_NANOAPP_RECEIVED_EXPECTED_ASYNC_EVENT_COUNT, 1); CREATE_CHRE_TEST_EVENT(CONCURRENT_NANOAPP_READ_COOKIE, 2); struct AppCookies { uint32_t sent = 0; uint32_t received = 0; }; constexpr uint64_t kAppOneId = 0x0123456789000001; constexpr uint64_t kAppTwoId = 0x0123456789000002; struct WifiScanTestConcurrentNanoappOne : public TestNanoapp { uint32_t perms = NanoappPermissions::CHRE_PERMS_WIFI; uint64_t id = kAppOneId; decltype(nanoappHandleEvent) *handleEvent = [](uint32_t, uint16_t eventType, const void *eventData) { constexpr uint8_t kExpectedReceiveAsyncResultCount = 2; static uint8_t receivedCookieCount = 0; static AppCookies appOneCookies; static AppCookies appTwoCookies; // Retrieve cookies from different apps that have the same access to // static storage due to inheritance. AppCookies *appCookies = chreGetAppId() == kAppTwoId ? &appTwoCookies : &appOneCookies; switch (eventType) { case CHRE_EVENT_WIFI_ASYNC_RESULT: { auto *event = static_cast(eventData); if (event->errorCode == CHRE_ERROR_NONE) { appCookies->received = *static_cast(event->cookie); ++receivedCookieCount; } else { LOGE("Received failed async result"); } if (receivedCookieCount == kExpectedReceiveAsyncResultCount) { TestEventQueueSingleton::get()->pushEvent( CONCURRENT_NANOAPP_RECEIVED_EXPECTED_ASYNC_EVENT_COUNT); } break; } case CHRE_EVENT_TEST_EVENT: { auto event = static_cast(eventData); bool success = false; uint32_t expectedCookie; switch (event->type) { case SCAN_REQUEST: appCookies->sent = *static_cast(event->data); success = chreWifiRequestScanAsyncDefault(&(appCookies->sent)); TestEventQueueSingleton::get()->pushEvent(SCAN_REQUEST, success); break; case CONCURRENT_NANOAPP_READ_COOKIE: TestEventQueueSingleton::get()->pushEvent( CONCURRENT_NANOAPP_READ_COOKIE, appCookies->received); break; } } }; }; }; struct WifiScanTestConcurrentNanoappTwo : public WifiScanTestConcurrentNanoappOne { uint64_t id = kAppTwoId; }; auto appOne = loadNanoapp(); auto appTwo = loadNanoapp(); constexpr uint32_t kAppOneRequestCookie = 0x1010; constexpr uint32_t kAppTwoRequestCookie = 0x2020; bool success; sendEventToNanoapp(appOne, SCAN_REQUEST, kAppOneRequestCookie); waitForEvent(SCAN_REQUEST, &success); EXPECT_TRUE(success); sendEventToNanoapp(appTwo, SCAN_REQUEST, kAppTwoRequestCookie); waitForEvent(SCAN_REQUEST, &success); EXPECT_TRUE(success); waitForEvent(CONCURRENT_NANOAPP_RECEIVED_EXPECTED_ASYNC_EVENT_COUNT); uint32_t receivedCookie; sendEventToNanoapp(appOne, CONCURRENT_NANOAPP_READ_COOKIE); waitForEvent(CONCURRENT_NANOAPP_READ_COOKIE, &receivedCookie); EXPECT_EQ(kAppOneRequestCookie, receivedCookie); sendEventToNanoapp(appTwo, CONCURRENT_NANOAPP_READ_COOKIE); waitForEvent(CONCURRENT_NANOAPP_READ_COOKIE, &receivedCookie); EXPECT_EQ(kAppTwoRequestCookie, receivedCookie); unloadNanoapp(appOne); unloadNanoapp(appTwo); } } // namespace } // namespace chre