1 /*
2 * Copyright (C) 2022 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 <cstdint>
18
19 #include "chre/core/event_loop_manager.h"
20 #include "chre/core/settings.h"
21 #include "chre/platform/linux/pal_nan.h"
22 #include "chre/platform/linux/pal_wifi.h"
23 #include "chre/platform/log.h"
24 #include "chre/util/system/napp_permissions.h"
25 #include "chre_api/chre/event.h"
26 #include "chre_api/chre/wifi.h"
27 #include "gtest/gtest.h"
28 #include "test_base.h"
29 #include "test_event.h"
30 #include "test_event_queue.h"
31 #include "test_util.h"
32
33 namespace chre {
34 namespace {
35
36 class WifiScanTest : public TestBase {};
37
38 using namespace std::chrono_literals;
39
40 CREATE_CHRE_TEST_EVENT(SCAN_REQUEST, 20);
41
42 struct WifiAsyncData {
43 const uint32_t *cookie;
44 chreError errorCode;
45 };
46
47 constexpr uint64_t kAppOneId = 0x0123456789000001;
48 constexpr uint64_t kAppTwoId = 0x0123456789000002;
49
50 class WifiScanRequestQueueTestBase : public TestBase {
51 public:
SetUp()52 void SetUp() {
53 TestBase::SetUp();
54 // Add delay to make sure the requests are queued.
55 chrePalWifiDelayResponse(PalWifiAsyncRequestTypes::SCAN,
56 /* milliseconds= */ 100ms);
57 }
58
TearDown()59 void TearDown() {
60 TestBase::TearDown();
61 chrePalWifiDelayResponse(PalWifiAsyncRequestTypes::SCAN,
62 /* milliseconds= */ 0ms);
63 }
64 };
65
66 class WifiScanTestNanoapp : public TestNanoapp {
67 public:
WifiScanTestNanoapp()68 WifiScanTestNanoapp()
69 : TestNanoapp(
70 TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
71
WifiScanTestNanoapp(uint64_t id)72 explicit WifiScanTestNanoapp(uint64_t id)
73 : TestNanoapp(TestNanoappInfo{
74 .id = id, .perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
75
handleEvent(uint32_t,uint16_t eventType,const void * eventData)76 void handleEvent(uint32_t, uint16_t eventType,
77 const void *eventData) override {
78 switch (eventType) {
79 case CHRE_EVENT_WIFI_ASYNC_RESULT: {
80 auto *event = static_cast<const chreAsyncResult *>(eventData);
81 TestEventQueueSingleton::get()->pushEvent(
82 CHRE_EVENT_WIFI_ASYNC_RESULT,
83 WifiAsyncData{
84 .cookie = static_cast<const uint32_t *>(event->cookie),
85 .errorCode = static_cast<chreError>(event->errorCode)});
86 break;
87 }
88
89 case CHRE_EVENT_WIFI_SCAN_RESULT: {
90 TestEventQueueSingleton::get()->pushEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
91 break;
92 }
93
94 case CHRE_EVENT_TEST_EVENT: {
95 auto event = static_cast<const TestEvent *>(eventData);
96 switch (event->type) {
97 case SCAN_REQUEST:
98 bool success = false;
99 if (mNextFreeCookieIndex < kMaxPendingCookie) {
100 mCookies[mNextFreeCookieIndex] =
101 *static_cast<uint32_t *>(event->data);
102 success = chreWifiRequestScanAsyncDefault(
103 &mCookies[mNextFreeCookieIndex]);
104 mNextFreeCookieIndex++;
105 } else {
106 LOGE("Too many cookies passed from test body!");
107 }
108 TestEventQueueSingleton::get()->pushEvent(SCAN_REQUEST, success);
109 }
110 }
111 }
112 }
113
114 protected:
115 static constexpr uint8_t kMaxPendingCookie = 10;
116 uint32_t mCookies[kMaxPendingCookie];
117 uint8_t mNextFreeCookieIndex = 0;
118 };
119
TEST_F(WifiScanTest,WifiScanBasicSettingTest)120 TEST_F(WifiScanTest, WifiScanBasicSettingTest) {
121 uint64_t appId = loadNanoapp(MakeUnique<WifiScanTestNanoapp>());
122
123 EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
124 Setting::WIFI_AVAILABLE, true /* enabled */);
125
126 constexpr uint32_t firstCookie = 0x1010;
127 bool success;
128 WifiAsyncData wifiAsyncData;
129
130 sendEventToNanoapp(appId, SCAN_REQUEST, firstCookie);
131 waitForEvent(SCAN_REQUEST, &success);
132 EXPECT_TRUE(success);
133
134 waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT, &wifiAsyncData);
135 EXPECT_EQ(wifiAsyncData.errorCode, CHRE_ERROR_NONE);
136 EXPECT_EQ(*wifiAsyncData.cookie, firstCookie);
137 waitForEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
138
139 EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
140 Setting::WIFI_AVAILABLE, false /* enabled */);
141
142 constexpr uint32_t secondCookie = 0x2020;
143 sendEventToNanoapp(appId, SCAN_REQUEST, secondCookie);
144 waitForEvent(SCAN_REQUEST, &success);
145 EXPECT_TRUE(success);
146
147 waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT, &wifiAsyncData);
148 EXPECT_EQ(wifiAsyncData.errorCode, CHRE_ERROR_FUNCTION_DISABLED);
149 EXPECT_EQ(*wifiAsyncData.cookie, secondCookie);
150
151 EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
152 Setting::WIFI_AVAILABLE, true /* enabled */);
153 unloadNanoapp(appId);
154 }
155
TEST_F(WifiScanRequestQueueTestBase,WifiQueuedScanSettingChangeTest)156 TEST_F(WifiScanRequestQueueTestBase, WifiQueuedScanSettingChangeTest) {
157 CREATE_CHRE_TEST_EVENT(CONCURRENT_NANOAPP_RECEIVED_EXPECTED_ASYNC_EVENT_COUNT,
158 1);
159 CREATE_CHRE_TEST_EVENT(CONCURRENT_NANOAPP_READ_ASYNC_EVENT, 2);
160 // Expecting to receive two event, one from each nanoapp.
161 constexpr uint8_t kExpectedReceiveAsyncResultCount = 2;
162 // receivedAsyncEventCount is shared across apps and must be static.
163 // But we want it initialized each time the test is executed.
164 static uint8_t receivedAsyncEventCount;
165 receivedAsyncEventCount = 0;
166
167 class WifiScanTestConcurrentNanoapp : public TestNanoapp {
168 public:
169 explicit WifiScanTestConcurrentNanoapp(uint64_t id)
170 : TestNanoapp(TestNanoappInfo{
171 .id = id, .perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
172
173 void handleEvent(uint32_t, uint16_t eventType,
174 const void *eventData) override {
175 switch (eventType) {
176 case CHRE_EVENT_WIFI_ASYNC_RESULT: {
177 auto *event = static_cast<const chreAsyncResult *>(eventData);
178 mReceivedAsyncResult = WifiAsyncData{
179 .cookie = static_cast<const uint32_t *>(event->cookie),
180 .errorCode = static_cast<chreError>(event->errorCode)};
181 ++receivedAsyncEventCount;
182 break;
183 }
184
185 case CHRE_EVENT_TEST_EVENT: {
186 auto event = static_cast<const TestEvent *>(eventData);
187 bool success = false;
188 switch (event->type) {
189 case SCAN_REQUEST:
190 mSentCookie = *static_cast<uint32_t *>(event->data);
191 success = chreWifiRequestScanAsyncDefault(&(mSentCookie));
192 TestEventQueueSingleton::get()->pushEvent(SCAN_REQUEST, success);
193 break;
194 case CONCURRENT_NANOAPP_READ_ASYNC_EVENT:
195 TestEventQueueSingleton::get()->pushEvent(
196 CONCURRENT_NANOAPP_READ_ASYNC_EVENT, mReceivedAsyncResult);
197 break;
198 }
199 }
200 }
201
202 if (receivedAsyncEventCount == kExpectedReceiveAsyncResultCount) {
203 TestEventQueueSingleton::get()->pushEvent(
204 CONCURRENT_NANOAPP_RECEIVED_EXPECTED_ASYNC_EVENT_COUNT);
205 }
206 }
207
208 protected:
209 uint32_t mSentCookie;
210 WifiAsyncData mReceivedAsyncResult;
211 };
212
213 uint64_t appOneId =
214 loadNanoapp(MakeUnique<WifiScanTestConcurrentNanoapp>(kAppOneId));
215 uint64_t appTwoId =
216 loadNanoapp(MakeUnique<WifiScanTestConcurrentNanoapp>(kAppTwoId));
217
218 constexpr uint32_t appOneRequestCookie = 0x1010;
219 constexpr uint32_t appTwoRequestCookie = 0x2020;
220 bool success;
221 sendEventToNanoapp(appOneId, SCAN_REQUEST, appOneRequestCookie);
222 waitForEvent(SCAN_REQUEST, &success);
223 EXPECT_TRUE(success);
224 sendEventToNanoapp(appTwoId, SCAN_REQUEST, appTwoRequestCookie);
225 waitForEvent(SCAN_REQUEST, &success);
226 EXPECT_TRUE(success);
227
228 EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
229 Setting::WIFI_AVAILABLE, false /* enabled */);
230
231 // We need to make sure that each nanoapp has received one async result before
232 // further analysis.
233 waitForEvent(CONCURRENT_NANOAPP_RECEIVED_EXPECTED_ASYNC_EVENT_COUNT);
234
235 WifiAsyncData wifiAsyncData;
236 sendEventToNanoapp(appOneId, CONCURRENT_NANOAPP_READ_ASYNC_EVENT);
237 waitForEvent(CONCURRENT_NANOAPP_READ_ASYNC_EVENT, &wifiAsyncData);
238 EXPECT_EQ(wifiAsyncData.errorCode, CHRE_ERROR_NONE);
239 EXPECT_EQ(*wifiAsyncData.cookie, appOneRequestCookie);
240
241 sendEventToNanoapp(appTwoId, CONCURRENT_NANOAPP_READ_ASYNC_EVENT);
242 waitForEvent(CONCURRENT_NANOAPP_READ_ASYNC_EVENT, &wifiAsyncData);
243 EXPECT_EQ(wifiAsyncData.errorCode, CHRE_ERROR_FUNCTION_DISABLED);
244 EXPECT_EQ(*wifiAsyncData.cookie, appTwoRequestCookie);
245
246 EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
247 Setting::WIFI_AVAILABLE, true /* enabled */);
248
249 unloadNanoapp(appOneId);
250 unloadNanoapp(appTwoId);
251 }
252
TEST_F(WifiScanRequestQueueTestBase,WifiScanRejectRequestFromSameNanoapp)253 TEST_F(WifiScanRequestQueueTestBase, WifiScanRejectRequestFromSameNanoapp) {
254 CREATE_CHRE_TEST_EVENT(RECEIVED_ALL_EXPECTED_EVENTS, 1);
255 CREATE_CHRE_TEST_EVENT(READ_ASYNC_EVENT, 2);
256
257 static constexpr uint8_t kExpectedReceivedScanRequestCount = 2;
258
259 class WifiScanTestBufferedAsyncResultNanoapp : public TestNanoapp {
260 public:
261 WifiScanTestBufferedAsyncResultNanoapp()
262 : TestNanoapp(
263 TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
264
265 void handleEvent(uint32_t, uint16_t eventType,
266 const void *eventData) override {
267 switch (eventType) {
268 case CHRE_EVENT_WIFI_ASYNC_RESULT: {
269 auto *event = static_cast<const chreAsyncResult *>(eventData);
270 mReceivedAsyncResult = WifiAsyncData{
271 .cookie = static_cast<const uint32_t *>(event->cookie),
272 .errorCode = static_cast<chreError>(event->errorCode)};
273 ++mReceivedAsyncEventCount;
274 break;
275 }
276
277 case CHRE_EVENT_TEST_EVENT: {
278 auto event = static_cast<const TestEvent *>(eventData);
279 bool success = false;
280 switch (event->type) {
281 case SCAN_REQUEST:
282 if (mReceivedScanRequestCount >=
283 kExpectedReceivedScanRequestCount) {
284 LOGE("Asking too many scan request");
285 } else {
286 mReceivedCookies[mReceivedScanRequestCount] =
287 *static_cast<uint32_t *>(event->data);
288 success = chreWifiRequestScanAsyncDefault(
289 &(mReceivedCookies[mReceivedScanRequestCount]));
290 ++mReceivedScanRequestCount;
291 TestEventQueueSingleton::get()->pushEvent(SCAN_REQUEST,
292 success);
293 }
294 break;
295 case READ_ASYNC_EVENT:
296 TestEventQueueSingleton::get()->pushEvent(READ_ASYNC_EVENT,
297 mReceivedAsyncResult);
298 break;
299 }
300 }
301 }
302 if (mReceivedAsyncEventCount == kExpectedReceivedAsyncResultCount &&
303 mReceivedScanRequestCount == kExpectedReceivedScanRequestCount) {
304 TestEventQueueSingleton::get()->pushEvent(RECEIVED_ALL_EXPECTED_EVENTS);
305 }
306 }
307
308 protected:
309 // We are only expecting to receive one async result since the second
310 // request is expected to fail.
311 const uint8_t kExpectedReceivedAsyncResultCount = 1;
312 uint8_t mReceivedAsyncEventCount = 0;
313 uint8_t mReceivedScanRequestCount = 0;
314
315 // We need to have two cookie storage to separate the two scan request.
316 uint32_t mReceivedCookies[kExpectedReceivedScanRequestCount];
317 WifiAsyncData mReceivedAsyncResult;
318 };
319
320 uint64_t appId =
321 loadNanoapp(MakeUnique<WifiScanTestBufferedAsyncResultNanoapp>());
322
323 constexpr uint32_t kFirstRequestCookie = 0x1010;
324 constexpr uint32_t kSecondRequestCookie = 0x2020;
325 bool success;
326 sendEventToNanoapp(appId, SCAN_REQUEST, kFirstRequestCookie);
327 waitForEvent(SCAN_REQUEST, &success);
328 EXPECT_TRUE(success);
329 sendEventToNanoapp(appId, SCAN_REQUEST, kSecondRequestCookie);
330 waitForEvent(SCAN_REQUEST, &success);
331 EXPECT_FALSE(success);
332
333 // We need to make sure that the nanoapp has received one async result and did
334 // two scan requests before further analysis.
335 waitForEvent(RECEIVED_ALL_EXPECTED_EVENTS);
336
337 WifiAsyncData wifiAsyncData;
338 sendEventToNanoapp(appId, READ_ASYNC_EVENT);
339 waitForEvent(READ_ASYNC_EVENT, &wifiAsyncData);
340 EXPECT_EQ(wifiAsyncData.errorCode, CHRE_ERROR_NONE);
341 EXPECT_EQ(*wifiAsyncData.cookie, kFirstRequestCookie);
342
343 unloadNanoapp(appId);
344 }
345
TEST_F(WifiScanRequestQueueTestBase,WifiScanActiveScanFromDistinctNanoapps)346 TEST_F(WifiScanRequestQueueTestBase, WifiScanActiveScanFromDistinctNanoapps) {
347 CREATE_CHRE_TEST_EVENT(CONCURRENT_NANOAPP_RECEIVED_EXPECTED_ASYNC_EVENT_COUNT,
348 1);
349 CREATE_CHRE_TEST_EVENT(CONCURRENT_NANOAPP_READ_COOKIE, 2);
350
351 constexpr uint8_t kExpectedReceiveAsyncResultCount = 2;
352 // receivedCookieCount is shared across apps and must be static.
353 // But we want it initialized each time the test is executed.
354 static uint8_t receivedCookieCount;
355 receivedCookieCount = 0;
356
357 class WifiScanTestConcurrentNanoapp : public TestNanoapp {
358 public:
359 explicit WifiScanTestConcurrentNanoapp(uint64_t id)
360 : TestNanoapp(TestNanoappInfo{
361 .id = id, .perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
362
363 void handleEvent(uint32_t, uint16_t eventType,
364 const void *eventData) override {
365 switch (eventType) {
366 case CHRE_EVENT_WIFI_ASYNC_RESULT: {
367 auto *event = static_cast<const chreAsyncResult *>(eventData);
368 if (event->errorCode == CHRE_ERROR_NONE) {
369 mReceivedCookie = *static_cast<const uint32_t *>(event->cookie);
370 ++receivedCookieCount;
371 } else {
372 LOGE("Received failed async result");
373 }
374
375 if (receivedCookieCount == kExpectedReceiveAsyncResultCount) {
376 TestEventQueueSingleton::get()->pushEvent(
377 CONCURRENT_NANOAPP_RECEIVED_EXPECTED_ASYNC_EVENT_COUNT);
378 }
379 break;
380 }
381
382 case CHRE_EVENT_TEST_EVENT: {
383 auto event = static_cast<const TestEvent *>(eventData);
384 bool success = false;
385 switch (event->type) {
386 case SCAN_REQUEST:
387 mSentCookie = *static_cast<uint32_t *>(event->data);
388 success = chreWifiRequestScanAsyncDefault(&(mSentCookie));
389 TestEventQueueSingleton::get()->pushEvent(SCAN_REQUEST, success);
390 break;
391 case CONCURRENT_NANOAPP_READ_COOKIE:
392 TestEventQueueSingleton::get()->pushEvent(
393 CONCURRENT_NANOAPP_READ_COOKIE, mReceivedCookie);
394 break;
395 }
396 }
397 }
398 }
399
400 protected:
401 uint32_t mSentCookie;
402 uint32_t mReceivedCookie;
403 };
404
405 uint64_t appOneId =
406 loadNanoapp(MakeUnique<WifiScanTestConcurrentNanoapp>(kAppOneId));
407 uint64_t appTwoId =
408 loadNanoapp(MakeUnique<WifiScanTestConcurrentNanoapp>(kAppTwoId));
409
410 constexpr uint32_t kAppOneRequestCookie = 0x1010;
411 constexpr uint32_t kAppTwoRequestCookie = 0x2020;
412 bool success;
413 sendEventToNanoapp(appOneId, SCAN_REQUEST, kAppOneRequestCookie);
414 waitForEvent(SCAN_REQUEST, &success);
415 EXPECT_TRUE(success);
416 sendEventToNanoapp(appTwoId, SCAN_REQUEST, kAppTwoRequestCookie);
417 waitForEvent(SCAN_REQUEST, &success);
418 EXPECT_TRUE(success);
419
420 waitForEvent(CONCURRENT_NANOAPP_RECEIVED_EXPECTED_ASYNC_EVENT_COUNT);
421
422 uint32_t receivedCookie;
423 sendEventToNanoapp(appOneId, CONCURRENT_NANOAPP_READ_COOKIE);
424 waitForEvent(CONCURRENT_NANOAPP_READ_COOKIE, &receivedCookie);
425 EXPECT_EQ(kAppOneRequestCookie, receivedCookie);
426
427 sendEventToNanoapp(appTwoId, CONCURRENT_NANOAPP_READ_COOKIE);
428 waitForEvent(CONCURRENT_NANOAPP_READ_COOKIE, &receivedCookie);
429 EXPECT_EQ(kAppTwoRequestCookie, receivedCookie);
430
431 unloadNanoapp(appOneId);
432 unloadNanoapp(appTwoId);
433 }
434
435 } // namespace
436 } // namespace chre