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
logChreWifiResult(const chreWifiScanResult & result)80 void logChreWifiResult(const chreWifiScanResult &result) {
81 const char *ssidStr = "<non-printable>";
82 char ssidBuffer[chre::kMaxSsidStrLen];
83 if (result.ssidLen == 0) {
84 ssidStr = "<empty>";
85 } else if (chre::parseSsidToStr(ssidBuffer, sizeof(ssidBuffer), result.ssid,
86 result.ssidLen)) {
87 ssidStr = ssidBuffer;
88 }
89
90 LOGI("Found network with SSID: %s", ssidStr);
91 const char *bssidStr = "<non-printable>";
92 char bssidBuffer[chre::kBssidStrLen];
93 if (chre::parseBssidToStr(result.bssid, bssidBuffer, sizeof(bssidBuffer))) {
94 bssidStr = bssidBuffer;
95 }
96
97 LOGI(" age (ms): %" PRIu32, result.ageMs);
98 LOGI(" capability info: 0x%" PRIx16, result.capabilityInfo);
99 LOGI(" bssid: %s", bssidStr);
100 LOGI(" flags: 0x%" PRIx8, result.flags);
101 LOGI(" rssi: %" PRId8 "dBm", result.rssi);
102 LOGI(" band: %s (%" PRIu8 ")", chre::parseChreWifiBand(result.band),
103 result.band);
104 LOGI(" primary channel: %" PRIu32, result.primaryChannel);
105 LOGI(" center frequency primary: %" PRIu32, result.centerFreqPrimary);
106 LOGI(" center frequency secondary: %" PRIu32, result.centerFreqSecondary);
107 LOGI(" channel width: %" PRIu8, result.channelWidth);
108 LOGI(" security mode: 0x%" PRIx8, result.securityMode);
109 }
110
111 } // anonymous namespace
112
SetUp()113 void PalWifiTest::SetUp() {
114 api_ = chrePalWifiGetApi(CHRE_PAL_WIFI_API_CURRENT_VERSION);
115 ASSERT_NE(api_, nullptr);
116 EXPECT_EQ(api_->moduleVersion, CHRE_PAL_WIFI_API_CURRENT_VERSION);
117
118 // Open the PAL API
119 static const struct chrePalWifiCallbacks kCallbacks = {
120 .scanMonitorStatusChangeCallback = chrePalScanMonitorStatusChangeCallback,
121 .scanResponseCallback = chrePalScanResponseCallback,
122 .scanEventCallback = chrePalScanEventCallback,
123 .rangingEventCallback = chrePalRangingEventCallback,
124 };
125 ASSERT_TRUE(api_->open(&chre::gChrePalSystemApi, &kCallbacks));
126 gTest = this;
127
128 errorCode_ = CHRE_ERROR_LAST;
129 numScanResultCount_ = 0;
130 lastScanEventReceived_ = false;
131 scanEventList_.clear();
132 scanParams_.reset();
133 lastEventIndex_ = UINT8_MAX;
134 scanMonitorEnabled_ = false;
135 }
136
TearDown()137 void PalWifiTest::TearDown() {
138 gTest = nullptr;
139 api_->close();
140 }
141
scanMonitorStatusChangeCallback(bool enabled,uint8_t errorCode)142 void PalWifiTest::scanMonitorStatusChangeCallback(bool enabled,
143 uint8_t errorCode) {
144 LOGI("Received scan monitor response with enabled %d error %" PRIu8, enabled,
145 errorCode);
146 if (errorCode == CHRE_ERROR_LAST) {
147 LOGE("Received CHRE_ERROR_LAST");
148 errorCode = CHRE_ERROR;
149 }
150 chre::LockGuard<chre::Mutex> lock(mutex_);
151 scanMonitorEnabled_ = enabled;
152 errorCode_ = errorCode;
153 condVar_.notify_one();
154 }
155
scanResponseCallback(bool pending,uint8_t errorCode)156 void PalWifiTest::scanResponseCallback(bool pending, uint8_t errorCode) {
157 LOGI("Received scan response with pending %d error %" PRIu8, pending,
158 errorCode);
159 if (errorCode == CHRE_ERROR_LAST) {
160 LOGE("Received CHRE_ERROR_LAST");
161 errorCode = CHRE_ERROR;
162 }
163 chre::LockGuard<chre::Mutex> lock(mutex_);
164 errorCode_ = errorCode;
165 condVar_.notify_one();
166 }
167
scanEventCallback(struct chreWifiScanEvent * event)168 void PalWifiTest::scanEventCallback(struct chreWifiScanEvent *event) {
169 if (event == nullptr) {
170 LOGE("Got null scan event");
171 } else {
172 {
173 chre::LockGuard<chre::Mutex> lock(mutex_);
174 scanEventList_.push_back(event);
175 numScanResultCount_ += event->resultCount;
176 lastScanEventReceived_ = (numScanResultCount_ == event->resultTotal);
177 }
178
179 condVar_.notify_one();
180 }
181 }
182
rangingEventCallback(uint8_t errorCode,struct chreWifiRangingEvent * event)183 void PalWifiTest::rangingEventCallback(uint8_t errorCode,
184 struct chreWifiRangingEvent *event) {
185 // TODO:
186 }
187
validateWifiScanEvent(const chreWifiScanEvent & event)188 void PalWifiTest::validateWifiScanEvent(const chreWifiScanEvent &event) {
189 if (scanParams_.has_value()) {
190 EXPECT_EQ(event.scanType, scanParams_->scanType);
191 EXPECT_GE(event.referenceTime,
192 chreGetTime() - (scanParams_->maxScanAgeMs *
193 chre::kOneMillisecondInNanoseconds));
194 EXPECT_EQ(event.radioChainPref, scanParams_->radioChainPref);
195 EXPECT_EQ(event.eventIndex, static_cast<uint8_t>(lastEventIndex_ + 1));
196 }
197 }
198
waitForAsyncResponseAssertSuccess(chre::Nanoseconds timeoutNs)199 void PalWifiTest::waitForAsyncResponseAssertSuccess(
200 chre::Nanoseconds timeoutNs) {
201 bool waitSuccess = true;
202 while (errorCode_ == CHRE_ERROR_LAST && waitSuccess) {
203 waitSuccess = condVar_.wait_for(mutex_, timeoutNs);
204 }
205 ASSERT_TRUE(waitSuccess);
206 ASSERT_EQ(errorCode_, CHRE_ERROR_NONE);
207 }
208
TEST_F(PalWifiTest,ScanAsyncTest)209 TEST_F(PalWifiTest, ScanAsyncTest) {
210 bool hasOnDemandScanCapability =
211 (api_->getCapabilities() & CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN) ==
212 CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN;
213 #if PAL_IMPL_TEST_WIFI_ON_DEMAND_SCAN_REQUIRED
214 ASSERT_TRUE(hasOnDemandScanCapability);
215 #else
216 if (!hasOnDemandScanCapability) {
217 GTEST_SKIP();
218 }
219 #endif
220
221 // Request a WiFi scan
222 chre::LockGuard<chre::Mutex> lock(mutex_);
223
224 struct chreWifiScanParams params = {};
225 params.scanType = CHRE_WIFI_SCAN_TYPE_ACTIVE;
226 params.maxScanAgeMs = 5000; // 5 seconds
227 params.frequencyListLen = 0;
228 params.ssidListLen = 0;
229 params.radioChainPref = CHRE_WIFI_RADIO_CHAIN_PREF_DEFAULT;
230 scanParams_ = params;
231
232 prepareForAsyncResponse();
233 ASSERT_TRUE(api_->requestScan(&scanParams_.value()));
234 waitForAsyncResponseAssertSuccess(kScanResultTimeoutNs);
235
236 // The CHRE API only poses timeout requirements on the async response. Use
237 // the same timeout to receive the scan results to avoid blocking forever.
238 bool waitSuccess = true;
239 while (!lastScanEventReceived_ && waitSuccess) {
240 waitSuccess = condVar_.wait_for(mutex_, kScanResultTimeoutNs);
241 }
242
243 for (auto *event : scanEventList_) {
244 for (uint8_t i = 0; i < event->resultCount; i++) {
245 const chreWifiScanResult &result = event->results[i];
246 logChreWifiResult(result);
247 }
248 validateWifiScanEvent(*event);
249
250 lastEventIndex_ = event->eventIndex;
251 api_->releaseScanEvent(event);
252 }
253
254 EXPECT_TRUE(lastScanEventReceived_);
255 EXPECT_GT(numScanResultCount_, 0);
256 }
257
258 // Note: This test only verifies that the scan monitor succeeds according
259 // to the async response.
TEST_F(PalWifiTest,ScanMonitorTest)260 TEST_F(PalWifiTest, ScanMonitorTest) {
261 bool hasScanMonitoringCapability =
262 (api_->getCapabilities() & CHRE_WIFI_CAPABILITIES_SCAN_MONITORING) ==
263 CHRE_WIFI_CAPABILITIES_SCAN_MONITORING;
264 #if PAL_IMPL_TEST_WIFI_SCAN_MONITORING_REQUIRED
265 ASSERT_TRUE(hasScanMonitoringCapability);
266 #else
267 if (!hasScanMonitoringCapability) {
268 GTEST_SKIP();
269 }
270 #endif
271
272 chre::LockGuard<chre::Mutex> lock(mutex_);
273
274 prepareForAsyncResponse();
275 ASSERT_TRUE(api_->configureScanMonitor(true /* enable */));
276 waitForAsyncResponseAssertSuccess(kAsyncResultTimeoutNs);
277 ASSERT_TRUE(scanMonitorEnabled_);
278
279 prepareForAsyncResponse();
280 ASSERT_TRUE(api_->configureScanMonitor(false /* enable */));
281 waitForAsyncResponseAssertSuccess(kAsyncResultTimeoutNs);
282 ASSERT_FALSE(scanMonitorEnabled_);
283 }
284
285 } // namespace wifi_pal_impl_test
286