xref: /aosp_15_r20/system/chre/pal/tests/src/wifi_pal_impl_test.cc (revision 84e339476a462649f82315436d70fd732297a399)
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