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