1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "wifi_pal_impl_test.h"
18
19 #include "chre/platform/log.h"
20 #include "chre/platform/shared/pal_system_api.h"
21 #include "chre/platform/system_time.h"
22 #include "chre/util/lock_guard.h"
23 #include "chre/util/nanoapp/wifi.h"
24
25 #include <cinttypes>
26
27 // Flag to require on-demand WiFi scanning capability to be enabled for the test
28 // to pass. Set to false to allow tests to pass on disabled platforms.
29 #ifndef PAL_IMPL_TEST_WIFI_ON_DEMAND_SCAN_REQUIRED
30 #define PAL_IMPL_TEST_WIFI_ON_DEMAND_SCAN_REQUIRED true
31 #endif
32
33 // Same as above for scan monitoring.
34 #ifndef PAL_IMPL_TEST_WIFI_SCAN_MONITORING_REQUIRED
35 #define PAL_IMPL_TEST_WIFI_SCAN_MONITORING_REQUIRED true
36 #endif
37
38 namespace wifi_pal_impl_test {
39
40 namespace {
41
42 using ::chre::Nanoseconds;
43 using ::chre::Seconds;
44 using ::chre::SystemTime;
45
46 //! A pointer to the current test running
47 wifi_pal_impl_test::PalWifiTest *gTest = nullptr;
48
49 //! Timeout as specified by the CHRE API
50 const Nanoseconds kAsyncResultTimeoutNs =
51 Nanoseconds(CHRE_ASYNC_RESULT_TIMEOUT_NS);
52 const Nanoseconds kScanResultTimeoutNs =
53 Nanoseconds(CHRE_WIFI_SCAN_RESULT_TIMEOUT_NS);
54
chrePalScanMonitorStatusChangeCallback(bool enabled,uint8_t errorCode)55 void chrePalScanMonitorStatusChangeCallback(bool enabled, uint8_t errorCode) {
56 if (gTest != nullptr) {
57 gTest->scanMonitorStatusChangeCallback(enabled, errorCode);
58 }
59 }
60
chrePalScanResponseCallback(bool pending,uint8_t errorCode)61 void chrePalScanResponseCallback(bool pending, uint8_t errorCode) {
62 if (gTest != nullptr) {
63 gTest->scanResponseCallback(pending, errorCode);
64 }
65 }
66
chrePalScanEventCallback(struct chreWifiScanEvent * event)67 void chrePalScanEventCallback(struct chreWifiScanEvent *event) {
68 if (gTest != nullptr) {
69 gTest->scanEventCallback(event);
70 }
71 }
72
chrePalRangingEventCallback(uint8_t errorCode,struct chreWifiRangingEvent * event)73 void chrePalRangingEventCallback(uint8_t errorCode,
74 struct chreWifiRangingEvent *event) {
75 if (gTest != nullptr) {
76 gTest->rangingEventCallback(errorCode, event);
77 }
78 }
79
80 } // anonymous namespace
81
SetUp()82 void PalWifiTest::SetUp() {
83 api_ = chrePalWifiGetApi(CHRE_PAL_WIFI_API_CURRENT_VERSION);
84 ASSERT_NE(api_, nullptr);
85 EXPECT_EQ(api_->moduleVersion, CHRE_PAL_WIFI_API_CURRENT_VERSION);
86
87 // Open the PAL API
88 static const struct chrePalWifiCallbacks kCallbacks = {
89 .scanMonitorStatusChangeCallback = chrePalScanMonitorStatusChangeCallback,
90 .scanResponseCallback = chrePalScanResponseCallback,
91 .scanEventCallback = chrePalScanEventCallback,
92 .rangingEventCallback = chrePalRangingEventCallback,
93 };
94 ASSERT_TRUE(api_->open(&chre::gChrePalSystemApi, &kCallbacks));
95 gTest = this;
96
97 errorCode_ = CHRE_ERROR_LAST;
98 numScanResultCount_ = 0;
99 lastScanEventReceived_ = false;
100 scanEventList_.clear();
101 scanParams_.reset();
102 lastEventIndex_ = UINT8_MAX;
103 scanMonitorEnabled_ = false;
104 }
105
TearDown()106 void PalWifiTest::TearDown() {
107 gTest = nullptr;
108 if (api_ != nullptr) {
109 api_->close();
110 }
111 }
112
scanMonitorStatusChangeCallback(bool enabled,uint8_t errorCode)113 void PalWifiTest::scanMonitorStatusChangeCallback(bool enabled,
114 uint8_t errorCode) {
115 LOGI("Received scan monitor response with enabled %d error %" PRIu8, enabled,
116 errorCode);
117 if (errorCode == CHRE_ERROR_LAST) {
118 LOGE("Received CHRE_ERROR_LAST");
119 errorCode = CHRE_ERROR;
120 }
121 chre::LockGuard<chre::Mutex> lock(mutex_);
122 scanMonitorEnabled_ = enabled;
123 errorCode_ = errorCode;
124 condVar_.notify_one();
125 }
126
scanResponseCallback(bool pending,uint8_t errorCode)127 void PalWifiTest::scanResponseCallback(bool pending, uint8_t errorCode) {
128 LOGI("Received scan response with pending %d error %" PRIu8, pending,
129 errorCode);
130 if (errorCode == CHRE_ERROR_LAST) {
131 LOGE("Received CHRE_ERROR_LAST");
132 errorCode = CHRE_ERROR;
133 }
134 chre::LockGuard<chre::Mutex> lock(mutex_);
135 errorCode_ = errorCode;
136 condVar_.notify_one();
137 }
138
scanEventCallback(struct chreWifiScanEvent * event)139 void PalWifiTest::scanEventCallback(struct chreWifiScanEvent *event) {
140 if (event == nullptr) {
141 LOGE("Got null scan event");
142 } else {
143 {
144 chre::LockGuard<chre::Mutex> lock(mutex_);
145 scanEventList_.push_back(event);
146 numScanResultCount_ += event->resultCount;
147 lastScanEventReceived_ = (numScanResultCount_ == event->resultTotal);
148 }
149
150 condVar_.notify_one();
151 }
152 }
153
rangingEventCallback(uint8_t errorCode,struct chreWifiRangingEvent * event)154 void PalWifiTest::rangingEventCallback(uint8_t errorCode,
155 struct chreWifiRangingEvent *event) {
156 // TODO:
157 }
158
validateWifiScanEvent(const chreWifiScanEvent & event)159 void PalWifiTest::validateWifiScanEvent(const chreWifiScanEvent &event) {
160 if (scanParams_.has_value()) {
161 EXPECT_EQ(event.scanType, scanParams_->scanType);
162 EXPECT_GE(event.referenceTime,
163 chreGetTime() - (scanParams_->maxScanAgeMs *
164 chre::kOneMillisecondInNanoseconds));
165 EXPECT_EQ(event.radioChainPref, scanParams_->radioChainPref);
166 EXPECT_EQ(event.eventIndex, static_cast<uint8_t>(lastEventIndex_ + 1));
167 }
168 }
169
waitForAsyncResponseAssertSuccess(chre::Nanoseconds timeoutNs)170 void PalWifiTest::waitForAsyncResponseAssertSuccess(
171 chre::Nanoseconds timeoutNs) {
172 bool waitSuccess = true;
173 while (errorCode_ == CHRE_ERROR_LAST && waitSuccess) {
174 waitSuccess = condVar_.wait_for(mutex_, timeoutNs);
175 }
176 ASSERT_TRUE(waitSuccess);
177 ASSERT_EQ(errorCode_, CHRE_ERROR_NONE);
178 }
179
TEST_F(PalWifiTest,ScanAsyncTest)180 TEST_F(PalWifiTest, ScanAsyncTest) {
181 bool hasOnDemandScanCapability =
182 (api_->getCapabilities() & CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN) ==
183 CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN;
184 #if PAL_IMPL_TEST_WIFI_ON_DEMAND_SCAN_REQUIRED
185 ASSERT_TRUE(hasOnDemandScanCapability);
186 #else
187 if (!hasOnDemandScanCapability) {
188 GTEST_SKIP();
189 }
190 #endif
191
192 // Request a WiFi scan
193 chre::LockGuard<chre::Mutex> lock(mutex_);
194
195 struct chreWifiScanParams params = {};
196 params.scanType = CHRE_WIFI_SCAN_TYPE_ACTIVE;
197 params.maxScanAgeMs = 5000; // 5 seconds
198 params.frequencyListLen = 0;
199 params.ssidListLen = 0;
200 params.radioChainPref = CHRE_WIFI_RADIO_CHAIN_PREF_DEFAULT;
201 scanParams_ = params;
202
203 prepareForAsyncResponse();
204 ASSERT_TRUE(api_->requestScan(&scanParams_.value()));
205 waitForAsyncResponseAssertSuccess(kScanResultTimeoutNs);
206
207 // The CHRE API only poses timeout requirements on the async response. Use
208 // the same timeout to receive the scan results to avoid blocking forever.
209 bool waitSuccess = true;
210 while (!lastScanEventReceived_ && waitSuccess) {
211 waitSuccess = condVar_.wait_for(mutex_, kScanResultTimeoutNs);
212 }
213
214 for (auto *event : scanEventList_) {
215 for (uint8_t i = 0; i < event->resultCount; i++) {
216 const chreWifiScanResult &result = event->results[i];
217 chre::logChreWifiResult(result);
218 }
219 validateWifiScanEvent(*event);
220
221 lastEventIndex_ = event->eventIndex;
222 api_->releaseScanEvent(event);
223 }
224
225 EXPECT_TRUE(lastScanEventReceived_);
226 EXPECT_GT(numScanResultCount_, 0u);
227 }
228
229 // Note: This test only verifies that the scan monitor succeeds according
230 // to the async response.
TEST_F(PalWifiTest,ScanMonitorTest)231 TEST_F(PalWifiTest, ScanMonitorTest) {
232 bool hasScanMonitoringCapability =
233 (api_->getCapabilities() & CHRE_WIFI_CAPABILITIES_SCAN_MONITORING) ==
234 CHRE_WIFI_CAPABILITIES_SCAN_MONITORING;
235 #if PAL_IMPL_TEST_WIFI_SCAN_MONITORING_REQUIRED
236 ASSERT_TRUE(hasScanMonitoringCapability);
237 #else
238 if (!hasScanMonitoringCapability) {
239 GTEST_SKIP();
240 }
241 #endif
242
243 chre::LockGuard<chre::Mutex> lock(mutex_);
244
245 prepareForAsyncResponse();
246 ASSERT_TRUE(api_->configureScanMonitor(true /* enable */));
247 waitForAsyncResponseAssertSuccess(kAsyncResultTimeoutNs);
248 ASSERT_TRUE(scanMonitorEnabled_);
249
250 prepareForAsyncResponse();
251 ASSERT_TRUE(api_->configureScanMonitor(false /* enable */));
252 waitForAsyncResponseAssertSuccess(kAsyncResultTimeoutNs);
253 ASSERT_FALSE(scanMonitorEnabled_);
254 }
255
256 } // namespace wifi_pal_impl_test
257