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 <cinttypes>
20
21 #include "chre/platform/linux/task_util/task_manager.h"
22 #include "chre/platform/log.h"
23 #include "chre/platform/shared/pal_system_api.h"
24 #include "chre/platform/system_time.h"
25 #include "chre/util/lock_guard.h"
26 #include "chre/util/macros.h"
27 #include "chre/util/nanoapp/wifi.h"
28
29 // Flag to require on-demand WiFi scanning capability to be enabled for the test
30 // to pass. Set to false to allow tests to pass on disabled platforms.
31 #ifndef PAL_IMPL_TEST_WIFI_ON_DEMAND_SCAN_REQUIRED
32 #define PAL_IMPL_TEST_WIFI_ON_DEMAND_SCAN_REQUIRED true
33 #endif
34
35 // Same as above for scan monitoring.
36 #ifndef PAL_IMPL_TEST_WIFI_SCAN_MONITORING_REQUIRED
37 #define PAL_IMPL_TEST_WIFI_SCAN_MONITORING_REQUIRED true
38 #endif
39
40 namespace wifi_pal_impl_test {
41
42 namespace {
43
44 using ::chre::Nanoseconds;
45 using ::chre::Seconds;
46 using ::chre::SystemTime;
47
48 //! A pointer to the current test running
49 wifi_pal_impl_test::PalWifiTest *gTest = nullptr;
50
51 //! Timeout as specified by the CHRE API
52 const Nanoseconds kAsyncResultTimeoutNs =
53 Nanoseconds(CHRE_ASYNC_RESULT_TIMEOUT_NS);
54 const Nanoseconds kScanResultTimeoutNs =
55 Nanoseconds(CHRE_WIFI_SCAN_RESULT_TIMEOUT_NS);
56
chrePalScanMonitorStatusChangeCallback(bool enabled,uint8_t errorCode)57 void chrePalScanMonitorStatusChangeCallback(bool enabled, uint8_t errorCode) {
58 if (gTest != nullptr) {
59 gTest->scanMonitorStatusChangeCallback(enabled, errorCode);
60 }
61 }
62
chrePalScanResponseCallback(bool pending,uint8_t errorCode)63 void chrePalScanResponseCallback(bool pending, uint8_t errorCode) {
64 if (gTest != nullptr) {
65 gTest->scanResponseCallback(pending, errorCode);
66 }
67 }
68
chrePalScanEventCallback(struct chreWifiScanEvent * event)69 void chrePalScanEventCallback(struct chreWifiScanEvent *event) {
70 if (gTest != nullptr) {
71 gTest->scanEventCallback(event);
72 }
73 }
74
chrePalRangingEventCallback(uint8_t errorCode,struct chreWifiRangingEvent * event)75 void chrePalRangingEventCallback(uint8_t errorCode,
76 struct chreWifiRangingEvent *event) {
77 if (gTest != nullptr) {
78 gTest->rangingEventCallback(errorCode, event);
79 }
80 }
81
chrePalNanServiceIdentifierCallback(uint8_t errorCode,uint32_t subscriptionId)82 void chrePalNanServiceIdentifierCallback(uint8_t errorCode,
83 uint32_t subscriptionId) {
84 if (gTest != nullptr) {
85 gTest->nanServiceIdentifierCallback(errorCode, subscriptionId);
86 }
87 }
88
chrePalNanServiceDiscoveryCallback(struct chreWifiNanDiscoveryEvent * event)89 void chrePalNanServiceDiscoveryCallback(
90 struct chreWifiNanDiscoveryEvent *event) {
91 if (gTest != nullptr) {
92 gTest->nanServiceDiscoveryCallback(event);
93 }
94 }
95
chrePalNanServiceLostCallback(uint32_t subscriptionId,uint32_t publisherId)96 void chrePalNanServiceLostCallback(uint32_t subscriptionId,
97 uint32_t publisherId) {
98 if (gTest != nullptr) {
99 gTest->nanServiceLostCallback(subscriptionId, publisherId);
100 }
101 }
102
chrePalNanServiceTerminatedCallback(uint32_t reason,uint32_t subscriptionId)103 void chrePalNanServiceTerminatedCallback(uint32_t reason,
104 uint32_t subscriptionId) {
105 if (gTest != nullptr) {
106 gTest->nanServiceTerminatedCallback(reason, subscriptionId);
107 }
108 }
109
chrePalNanSubscriptionCanceledCallback(uint8_t reason,uint32_t subscriptionId)110 void chrePalNanSubscriptionCanceledCallback(uint8_t reason,
111 uint32_t subscriptionId) {
112 if (gTest != nullptr) {
113 gTest->nanSubscriptionCanceledCallback(reason, subscriptionId);
114 }
115 }
116
117 } // anonymous namespace
118
SetUp()119 void PalWifiTest::SetUp() {
120 chre::TaskManagerSingleton::deinit();
121 chre::TaskManagerSingleton::init();
122 api_ = chrePalWifiGetApi(CHRE_PAL_WIFI_API_CURRENT_VERSION);
123 ASSERT_NE(api_, nullptr);
124 EXPECT_EQ(api_->moduleVersion, CHRE_PAL_WIFI_API_CURRENT_VERSION);
125
126 // Open the PAL API
127 static const struct chrePalWifiCallbacks kCallbacks = {
128 .scanMonitorStatusChangeCallback = chrePalScanMonitorStatusChangeCallback,
129 .scanResponseCallback = chrePalScanResponseCallback,
130 .scanEventCallback = chrePalScanEventCallback,
131 .rangingEventCallback = chrePalRangingEventCallback,
132 .nanServiceIdentifierCallback = chrePalNanServiceIdentifierCallback,
133 .nanServiceDiscoveryCallback = chrePalNanServiceDiscoveryCallback,
134 .nanServiceLostCallback = chrePalNanServiceLostCallback,
135 .nanServiceTerminatedCallback = chrePalNanServiceTerminatedCallback,
136 .nanSubscriptionCanceledCallback = chrePalNanSubscriptionCanceledCallback,
137 };
138 ASSERT_TRUE(api_->open(&chre::gChrePalSystemApi, &kCallbacks));
139 gTest = this;
140
141 errorCode_ = CHRE_ERROR_LAST;
142 numScanResultCount_ = 0;
143 lastScanEventReceived_ = false;
144 scanEventList_.clear();
145 scanParams_.reset();
146 lastEventIndex_ = UINT8_MAX;
147 scanMonitorEnabled_ = false;
148 }
149
TearDown()150 void PalWifiTest::TearDown() {
151 gTest = nullptr;
152 if (api_ != nullptr) {
153 api_->close();
154 }
155 chre::TaskManagerSingleton::deinit();
156 }
157
scanMonitorStatusChangeCallback(bool enabled,uint8_t errorCode)158 void PalWifiTest::scanMonitorStatusChangeCallback(bool enabled,
159 uint8_t errorCode) {
160 LOGI("Received scan monitor response with enabled %d error %" PRIu8, enabled,
161 errorCode);
162 if (errorCode == CHRE_ERROR_LAST) {
163 LOGE("Received CHRE_ERROR_LAST");
164 errorCode = CHRE_ERROR;
165 }
166 chre::LockGuard<chre::Mutex> lock(mutex_);
167 scanMonitorEnabled_ = enabled;
168 errorCode_ = errorCode;
169 condVar_.notify_one();
170 }
171
scanResponseCallback(bool pending,uint8_t errorCode)172 void PalWifiTest::scanResponseCallback(bool pending, uint8_t errorCode) {
173 LOGI("Received scan response with pending %d error %" PRIu8, pending,
174 errorCode);
175 if (errorCode == CHRE_ERROR_LAST) {
176 LOGE("Received CHRE_ERROR_LAST");
177 errorCode = CHRE_ERROR;
178 }
179 chre::LockGuard<chre::Mutex> lock(mutex_);
180 errorCode_ = errorCode;
181 condVar_.notify_one();
182 }
183
scanEventCallback(struct chreWifiScanEvent * event)184 void PalWifiTest::scanEventCallback(struct chreWifiScanEvent *event) {
185 if (event == nullptr) {
186 LOGE("Got null scan event");
187 } else {
188 {
189 chre::LockGuard<chre::Mutex> lock(mutex_);
190 scanEventList_.push_back(event);
191 numScanResultCount_ += event->resultCount;
192 lastScanEventReceived_ = (numScanResultCount_ == event->resultTotal);
193 }
194
195 condVar_.notify_one();
196 }
197 }
198
rangingEventCallback(uint8_t errorCode,struct chreWifiRangingEvent * event)199 void PalWifiTest::rangingEventCallback(uint8_t errorCode,
200 struct chreWifiRangingEvent *event) {
201 // TODO:
202 UNUSED_VAR(errorCode);
203 UNUSED_VAR(event);
204 }
205
nanServiceIdentifierCallback(uint8_t errorCode,uint32_t subscriptionId)206 void PalWifiTest::nanServiceIdentifierCallback(uint8_t errorCode,
207 uint32_t subscriptionId) {
208 chre::LockGuard<chre::Mutex> lock(mutex_);
209 subscriptionId_ = subscriptionId;
210 errorCode_ = errorCode;
211 condVar_.notify_one();
212 }
213
nanServiceDiscoveryCallback(struct chreWifiNanDiscoveryEvent * event)214 void PalWifiTest::nanServiceDiscoveryCallback(
215 struct chreWifiNanDiscoveryEvent *event) {
216 if (event == nullptr) {
217 LOGE("Got null discovery event");
218 } else {
219 errorCode_ = CHRE_ERROR_LAST;
220 publishId_ = event->publishId;
221 }
222 }
223
nanServiceLostCallback(uint32_t subscriptionId,uint32_t publisherId)224 void PalWifiTest::nanServiceLostCallback(uint32_t subscriptionId,
225 uint32_t publisherId) {
226 subscriptionId_ = subscriptionId;
227 publishId_ = publisherId;
228 }
229
nanServiceTerminatedCallback(uint32_t reason,uint32_t subscriptionId)230 void PalWifiTest::nanServiceTerminatedCallback(uint32_t reason,
231 uint32_t subscriptionId) {
232 subscriptionId_ = subscriptionId;
233 errorCode_ = reason;
234 }
235
nanSubscriptionCanceledCallback(uint8_t errorCode,uint32_t subscriptionId)236 void PalWifiTest::nanSubscriptionCanceledCallback(uint8_t errorCode,
237 uint32_t subscriptionId) {
238 errorCode_ = errorCode;
239 subscriptionId_ = subscriptionId;
240 }
241
validateWifiScanEvent(const chreWifiScanEvent & event)242 void PalWifiTest::validateWifiScanEvent(const chreWifiScanEvent &event) {
243 if (scanParams_.has_value()) {
244 EXPECT_EQ(event.scanType, scanParams_->scanType);
245 EXPECT_GE(event.referenceTime,
246 chreGetTime() - (scanParams_->maxScanAgeMs *
247 chre::kOneMillisecondInNanoseconds));
248 EXPECT_EQ(event.radioChainPref, scanParams_->radioChainPref);
249 EXPECT_EQ(event.eventIndex, static_cast<uint8_t>(lastEventIndex_ + 1));
250 }
251 }
252
waitForAsyncResponseAssertSuccess(chre::Nanoseconds timeoutNs)253 void PalWifiTest::waitForAsyncResponseAssertSuccess(
254 chre::Nanoseconds timeoutNs) {
255 bool waitSuccess = true;
256 while (errorCode_ == CHRE_ERROR_LAST && waitSuccess) {
257 waitSuccess = condVar_.wait_for(mutex_, timeoutNs);
258 }
259 ASSERT_TRUE(waitSuccess);
260 ASSERT_EQ(errorCode_, CHRE_ERROR_NONE);
261 }
262
TEST_F(PalWifiTest,ScanAsyncTest)263 TEST_F(PalWifiTest, ScanAsyncTest) {
264 bool hasOnDemandScanCapability =
265 (api_->getCapabilities() & CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN) ==
266 CHRE_WIFI_CAPABILITIES_ON_DEMAND_SCAN;
267 #if PAL_IMPL_TEST_WIFI_ON_DEMAND_SCAN_REQUIRED
268 ASSERT_TRUE(hasOnDemandScanCapability);
269 #else
270 if (!hasOnDemandScanCapability) {
271 GTEST_SKIP();
272 }
273 #endif
274
275 // Request a WiFi scan
276 chre::LockGuard<chre::Mutex> lock(mutex_);
277
278 struct chreWifiScanParams params = {};
279 params.scanType = CHRE_WIFI_SCAN_TYPE_ACTIVE;
280 params.maxScanAgeMs = 5000; // 5 seconds
281 params.frequencyListLen = 0;
282 params.ssidListLen = 0;
283 params.radioChainPref = CHRE_WIFI_RADIO_CHAIN_PREF_DEFAULT;
284 scanParams_ = params;
285
286 prepareForAsyncResponse();
287 ASSERT_TRUE(api_->requestScan(&scanParams_.value()));
288 waitForAsyncResponseAssertSuccess(kScanResultTimeoutNs);
289
290 // The CHRE API only poses timeout requirements on the async response. Use
291 // the same timeout to receive the scan results to avoid blocking forever.
292 bool waitSuccess = true;
293 while (!lastScanEventReceived_ && waitSuccess) {
294 waitSuccess = condVar_.wait_for(mutex_, kScanResultTimeoutNs);
295 }
296
297 for (auto *event : scanEventList_) {
298 for (uint8_t i = 0; i < event->resultCount; i++) {
299 const chreWifiScanResult &result = event->results[i];
300 chre::logChreWifiResult(result);
301 }
302 validateWifiScanEvent(*event);
303
304 lastEventIndex_ = event->eventIndex;
305 api_->releaseScanEvent(event);
306 }
307
308 EXPECT_TRUE(lastScanEventReceived_);
309 EXPECT_GT(numScanResultCount_, 0u);
310 }
311
312 // Note: This test only verifies that the scan monitor succeeds according
313 // to the async response.
TEST_F(PalWifiTest,ScanMonitorTest)314 TEST_F(PalWifiTest, ScanMonitorTest) {
315 bool hasScanMonitoringCapability =
316 (api_->getCapabilities() & CHRE_WIFI_CAPABILITIES_SCAN_MONITORING) ==
317 CHRE_WIFI_CAPABILITIES_SCAN_MONITORING;
318 #if PAL_IMPL_TEST_WIFI_SCAN_MONITORING_REQUIRED
319 ASSERT_TRUE(hasScanMonitoringCapability);
320 #else
321 if (!hasScanMonitoringCapability) {
322 GTEST_SKIP();
323 }
324 #endif
325
326 chre::LockGuard<chre::Mutex> lock(mutex_);
327
328 prepareForAsyncResponse();
329 ASSERT_TRUE(api_->configureScanMonitor(true /* enable */));
330 waitForAsyncResponseAssertSuccess(kAsyncResultTimeoutNs);
331 ASSERT_TRUE(scanMonitorEnabled_);
332
333 prepareForAsyncResponse();
334 ASSERT_TRUE(api_->configureScanMonitor(false /* enable */));
335 waitForAsyncResponseAssertSuccess(kAsyncResultTimeoutNs);
336 ASSERT_FALSE(scanMonitorEnabled_);
337 }
338
339 /*
340 * Tests if NAN capabilities are available and requests a service
341 * subscription. The test is terminated if NAN capabilities are not
342 * available.
343 *
344 * NOTE: The subscription config currently is mostly a placeholder -
345 * please modify it appropriately when testing and/or validating service
346 * discovery.
347 */
TEST_F(PalWifiTest,NanSubscribeTest)348 TEST_F(PalWifiTest, NanSubscribeTest) {
349 bool hasNanCapabilities =
350 (api_->getCapabilities() & CHRE_WIFI_CAPABILITIES_NAN_SUB);
351 if (!hasNanCapabilities) {
352 GTEST_SKIP();
353 }
354
355 prepareForAsyncResponse();
356 struct chreWifiNanSubscribeConfig config = {
357 .subscribeType = CHRE_WIFI_NAN_SUBSCRIBE_TYPE_PASSIVE,
358 .service = "SomeService",
359 };
360 ASSERT_TRUE(api_->nanSubscribe(&config));
361 waitForAsyncResponseAssertSuccess(kAsyncResultTimeoutNs);
362 ASSERT_TRUE(subscriptionId_.has_value());
363 }
364
365 /*
366 * Tests if NAN capabilities are available and requests a service
367 * subscription, then requests a cancelation of the subscription.
368 * The test is terminated if NAN capabilities are not
369 * available.
370 *
371 * NOTE: The subscription config currently is mostly a placeholder -
372 * please modify it appropriately when testing and/or validating service
373 * discovery.
374 */
TEST_F(PalWifiTest,NanSubscribeCancelTest)375 TEST_F(PalWifiTest, NanSubscribeCancelTest) {
376 bool hasNanCapabilities =
377 (api_->getCapabilities() & CHRE_WIFI_CAPABILITIES_NAN_SUB);
378 if (!hasNanCapabilities) {
379 GTEST_SKIP();
380 }
381
382 prepareForAsyncResponse();
383 struct chreWifiNanSubscribeConfig config = {
384 .subscribeType = CHRE_WIFI_NAN_SUBSCRIBE_TYPE_PASSIVE,
385 .service = "SomeService",
386 };
387 ASSERT_TRUE(api_->nanSubscribe(&config));
388 waitForAsyncResponseAssertSuccess(kAsyncResultTimeoutNs);
389 ASSERT_TRUE(subscriptionId_.has_value());
390
391 prepareForAsyncResponse();
392 uint32_t cachedSubscriptionId = subscriptionId_.value();
393 subscriptionId_.reset();
394
395 ASSERT_TRUE(api_->nanSubscribeCancel(cachedSubscriptionId));
396 waitForAsyncResponseAssertSuccess(kAsyncResultTimeoutNs);
397 ASSERT_TRUE(subscriptionId_.has_value());
398 ASSERT_EQ(subscriptionId_.value(), cachedSubscriptionId);
399 }
400
401 } // namespace wifi_pal_impl_test
402