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