xref: /aosp_15_r20/system/chre/test/simulation/wifi_timeout_test.cc (revision 84e339476a462649f82315436d70fd732297a399)
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_wifi.h"
22 #include "chre/platform/log.h"
23 #include "chre/util/nanoapp/app_id.h"
24 #include "chre/util/system/napp_permissions.h"
25 #include "chre_api/chre/event.h"
26 #include "chre_api/chre/re.h"
27 #include "chre_api/chre/wifi.h"
28 #include "gtest/gtest.h"
29 #include "test_base.h"
30 #include "test_event.h"
31 #include "test_event_queue.h"
32 #include "test_util.h"
33 
34 namespace chre {
35 namespace {
36 // WifiTimeoutTestBase needs to set timeout more than the max waitForEvent()
37 // should process (Currently it is
38 // WifiCanDispatchSecondScanRequestInQueueAfterFirstTimeout). If not,
39 // waitForEvent will timeout before actual timeout happens in CHRE, making us
40 // unable to observe how system handles timeout.
41 class WifiTimeoutTestBase : public TestBase {
42  protected:
getTimeoutNs() const43   uint64_t getTimeoutNs() const override {
44     return 3 * CHRE_TEST_WIFI_SCAN_RESULT_TIMEOUT_NS;
45   }
46 };
47 
48 CREATE_CHRE_TEST_EVENT(SCAN_REQUEST, 20);
49 CREATE_CHRE_TEST_EVENT(REQUEST_TIMED_OUT, 21);
50 
TEST_F(WifiTimeoutTestBase,WifiScanRequestTimeoutTest)51 TEST_F(WifiTimeoutTestBase, WifiScanRequestTimeoutTest) {
52   class ScanTestNanoapp : public TestNanoapp {
53    public:
54     explicit ScanTestNanoapp()
55         : TestNanoapp(
56               TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
57 
58     bool start() override {
59       mRequestTimer = CHRE_TIMER_INVALID;
60       return true;
61     }
62 
63     void handleEvent(uint32_t, uint16_t eventType,
64                      const void *eventData) override {
65       switch (eventType) {
66         case CHRE_EVENT_WIFI_ASYNC_RESULT: {
67           auto *event = static_cast<const chreAsyncResult *>(eventData);
68           if (mRequestTimer != CHRE_TIMER_INVALID) {
69             chreTimerCancel(mRequestTimer);
70             mRequestTimer = CHRE_TIMER_INVALID;
71           }
72           if (event->success) {
73             TestEventQueueSingleton::get()->pushEvent(
74                 CHRE_EVENT_WIFI_ASYNC_RESULT,
75                 *(static_cast<const uint32_t *>(event->cookie)));
76           }
77           break;
78         }
79 
80         case CHRE_EVENT_WIFI_SCAN_RESULT: {
81           TestEventQueueSingleton::get()->pushEvent(
82               CHRE_EVENT_WIFI_SCAN_RESULT);
83           break;
84         }
85 
86         case CHRE_EVENT_TIMER: {
87           TestEventQueueSingleton::get()->pushEvent(REQUEST_TIMED_OUT);
88           mRequestTimer = CHRE_TIMER_INVALID;
89           break;
90         }
91 
92         case CHRE_EVENT_TEST_EVENT: {
93           auto event = static_cast<const TestEvent *>(eventData);
94           switch (event->type) {
95             case SCAN_REQUEST:
96               bool success = false;
97               mCookie = *static_cast<uint32_t *>(event->data);
98               if (chreWifiRequestScanAsyncDefault(&mCookie)) {
99                 mRequestTimer =
100                     chreTimerSet(CHRE_TEST_WIFI_SCAN_RESULT_TIMEOUT_NS, nullptr,
101                                  true /* oneShot */);
102                 success = mRequestTimer != CHRE_TIMER_INVALID;
103               }
104               TestEventQueueSingleton::get()->pushEvent(SCAN_REQUEST, success);
105               break;
106           }
107           break;
108         }
109       }
110     }
111 
112    protected:
113     uint32_t mCookie;
114     uint32_t mRequestTimer;
115   };
116 
117   uint64_t appId = loadNanoapp(MakeUnique<ScanTestNanoapp>());
118 
119   constexpr uint32_t timeOutCookie = 0xdead;
120   chrePalWifiEnableResponse(PalWifiAsyncRequestTypes::SCAN,
121                             false /* enableResponse */);
122   sendEventToNanoapp(appId, SCAN_REQUEST, timeOutCookie);
123   bool success;
124   waitForEvent(SCAN_REQUEST, &success);
125   EXPECT_TRUE(success);
126 
127   waitForEvent(REQUEST_TIMED_OUT);
128 
129   // Make sure that we can still request scan after a timedout
130   // request.
131   constexpr uint32_t successCookie = 0x0101;
132   chrePalWifiEnableResponse(PalWifiAsyncRequestTypes::SCAN,
133                             true /* enableResponse */);
134   sendEventToNanoapp(appId, SCAN_REQUEST, successCookie);
135   waitForEvent(SCAN_REQUEST, &success);
136   EXPECT_TRUE(success);
137   waitForEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
138 
139   unloadNanoapp(appId);
140 }
141 
TEST_F(WifiTimeoutTestBase,WifiCanDispatchQueuedRequestAfterOneTimeout)142 TEST_F(WifiTimeoutTestBase, WifiCanDispatchQueuedRequestAfterOneTimeout) {
143   constexpr uint8_t kNanoappNum = 2;
144   // receivedTimeout is shared across apps and must be static.
145   // But we want it initialized each time the test is executed.
146   static uint8_t receivedTimeout;
147   receivedTimeout = 0;
148 
149   class ScanTestNanoapp : public TestNanoapp {
150    public:
151     explicit ScanTestNanoapp(uint64_t id = kDefaultTestNanoappId)
152         : TestNanoapp(TestNanoappInfo{
153               .id = id, .perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
154 
155     bool start() override {
156       for (uint8_t i = 0; i < kNanoappNum; ++i) {
157         mRequestTimers[i] = CHRE_TIMER_INVALID;
158       }
159       return true;
160     }
161 
162     void handleEvent(uint32_t, uint16_t eventType,
163                      const void *eventData) override {
164       size_t index = id() - CHRE_VENDOR_ID_EXAMPLE - 1;
165       switch (eventType) {
166         case CHRE_EVENT_WIFI_ASYNC_RESULT: {
167           auto *event = static_cast<const chreAsyncResult *>(eventData);
168           if (mRequestTimers[index] != CHRE_TIMER_INVALID) {
169             chreTimerCancel(mRequestTimers[index]);
170             mRequestTimers[index] = CHRE_TIMER_INVALID;
171           }
172           if (event->success) {
173             TestEventQueueSingleton::get()->pushEvent(
174                 CHRE_EVENT_WIFI_ASYNC_RESULT,
175                 *(static_cast<const uint32_t *>(event->cookie)));
176           }
177           break;
178         }
179 
180         case CHRE_EVENT_WIFI_SCAN_RESULT: {
181           TestEventQueueSingleton::get()->pushEvent(
182               CHRE_EVENT_WIFI_SCAN_RESULT);
183           break;
184         }
185 
186         case CHRE_EVENT_TIMER: {
187           if (eventData == &mCookie[index]) {
188             receivedTimeout++;
189             mRequestTimers[index] = CHRE_TIMER_INVALID;
190           }
191           if (receivedTimeout == 2) {
192             TestEventQueueSingleton::get()->pushEvent(REQUEST_TIMED_OUT);
193           }
194           break;
195         }
196 
197         case CHRE_EVENT_TEST_EVENT: {
198           auto event = static_cast<const TestEvent *>(eventData);
199           switch (event->type) {
200             case SCAN_REQUEST:
201               bool success = false;
202               mCookie[index] = *static_cast<uint32_t *>(event->data);
203               if (chreWifiRequestScanAsyncDefault(&mCookie[index])) {
204                 mRequestTimers[index] =
205                     chreTimerSet(CHRE_TEST_WIFI_SCAN_RESULT_TIMEOUT_NS,
206                                  &mCookie[index], true /* oneShot */);
207                 success = mRequestTimers[index] != CHRE_TIMER_INVALID;
208               }
209               TestEventQueueSingleton::get()->pushEvent(SCAN_REQUEST, success);
210               break;
211           }
212           break;
213         }
214       }
215     }
216 
217    protected:
218     uint32_t mCookie[kNanoappNum];
219     uint32_t mRequestTimers[kNanoappNum];
220   };
221   constexpr uint64_t kAppOneId = makeExampleNanoappId(1);
222   constexpr uint64_t kAppTwoId = makeExampleNanoappId(2);
223 
224   uint64_t firstAppId = loadNanoapp(MakeUnique<ScanTestNanoapp>(kAppOneId));
225   uint64_t secondAppId = loadNanoapp(MakeUnique<ScanTestNanoapp>(kAppTwoId));
226 
227   constexpr uint32_t timeOutCookie = 0xdead;
228   chrePalWifiEnableResponse(PalWifiAsyncRequestTypes::SCAN,
229                             false /* enableResponse */);
230   bool success;
231   sendEventToNanoapp(firstAppId, SCAN_REQUEST, timeOutCookie);
232   waitForEvent(SCAN_REQUEST, &success);
233   EXPECT_TRUE(success);
234   sendEventToNanoapp(secondAppId, SCAN_REQUEST, timeOutCookie);
235   waitForEvent(SCAN_REQUEST, &success);
236   EXPECT_TRUE(success);
237 
238   waitForEvent(REQUEST_TIMED_OUT);
239 
240   // Make sure that we can still request scan for both nanoapps after a timedout
241   // request.
242   constexpr uint32_t successCookie = 0x0101;
243   chrePalWifiEnableResponse(PalWifiAsyncRequestTypes::SCAN,
244                             true /* enableResponse */);
245   sendEventToNanoapp(firstAppId, SCAN_REQUEST, successCookie);
246   waitForEvent(SCAN_REQUEST, &success);
247   EXPECT_TRUE(success);
248   waitForEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
249   sendEventToNanoapp(secondAppId, SCAN_REQUEST, successCookie);
250   waitForEvent(SCAN_REQUEST, &success);
251   EXPECT_TRUE(success);
252   waitForEvent(CHRE_EVENT_WIFI_SCAN_RESULT);
253 
254   unloadNanoapp(firstAppId);
255   unloadNanoapp(secondAppId);
256 }
257 
TEST_F(WifiTimeoutTestBase,WifiScanMonitorTimeoutTest)258 TEST_F(WifiTimeoutTestBase, WifiScanMonitorTimeoutTest) {
259   CREATE_CHRE_TEST_EVENT(SCAN_MONITOR_REQUEST, 1);
260 
261   struct MonitoringRequest {
262     bool enable;
263     uint32_t cookie;
264   };
265 
266   class App : public TestNanoapp {
267    public:
268     App()
269         : TestNanoapp(
270               TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
271 
272     bool start() override {
273       mRequestTimer = CHRE_TIMER_INVALID;
274       return true;
275     }
276 
277     void handleEvent(uint32_t, uint16_t eventType,
278                      const void *eventData) override {
279       switch (eventType) {
280         case CHRE_EVENT_WIFI_ASYNC_RESULT: {
281           auto *event = static_cast<const chreAsyncResult *>(eventData);
282           if (event->success) {
283             if (mRequestTimer != CHRE_TIMER_INVALID) {
284               chreTimerCancel(mRequestTimer);
285               mRequestTimer = CHRE_TIMER_INVALID;
286             }
287             TestEventQueueSingleton::get()->pushEvent(
288                 CHRE_EVENT_WIFI_ASYNC_RESULT,
289                 *(static_cast<const uint32_t *>(event->cookie)));
290           }
291           break;
292         }
293 
294         case CHRE_EVENT_TIMER: {
295           mRequestTimer = CHRE_TIMER_INVALID;
296           TestEventQueueSingleton::get()->pushEvent(REQUEST_TIMED_OUT);
297           break;
298         }
299 
300         case CHRE_EVENT_TEST_EVENT: {
301           auto event = static_cast<const TestEvent *>(eventData);
302           switch (event->type) {
303             case SCAN_MONITOR_REQUEST:
304               bool success = false;
305               auto request =
306                   static_cast<const MonitoringRequest *>(event->data);
307               if (chreWifiConfigureScanMonitorAsync(request->enable,
308                                                     &mCookie)) {
309                 mCookie = request->cookie;
310                 mRequestTimer = chreTimerSet(CHRE_TEST_ASYNC_RESULT_TIMEOUT_NS,
311                                              nullptr, true /* oneShot */);
312                 success = mRequestTimer != CHRE_TIMER_INVALID;
313               }
314 
315               TestEventQueueSingleton::get()->pushEvent(SCAN_MONITOR_REQUEST,
316                                                         success);
317           }
318         }
319       }
320     }
321 
322    protected:
323     uint32_t mCookie;
324     uint32_t mRequestTimer;
325   };
326 
327   uint64_t appId = loadNanoapp(MakeUnique<App>());
328 
329   MonitoringRequest timeoutRequest{.enable = true, .cookie = 0xdead};
330   chrePalWifiEnableResponse(PalWifiAsyncRequestTypes::SCAN_MONITORING, false);
331   sendEventToNanoapp(appId, SCAN_MONITOR_REQUEST, timeoutRequest);
332   bool success;
333   waitForEvent(SCAN_MONITOR_REQUEST, &success);
334   EXPECT_TRUE(success);
335 
336   waitForEvent(REQUEST_TIMED_OUT);
337 
338   // Make sure that we can still request to change scan monitor after a timedout
339   // request.
340   MonitoringRequest enableRequest{.enable = true, .cookie = 0x1010};
341   chrePalWifiEnableResponse(PalWifiAsyncRequestTypes::SCAN_MONITORING, true);
342   sendEventToNanoapp(appId, SCAN_MONITOR_REQUEST, enableRequest);
343   waitForEvent(SCAN_MONITOR_REQUEST, &success);
344   EXPECT_TRUE(success);
345 
346   uint32_t cookie;
347   waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT, &cookie);
348   EXPECT_EQ(cookie, enableRequest.cookie);
349   EXPECT_TRUE(chrePalWifiIsScanMonitoringActive());
350 
351   MonitoringRequest disableRequest{.enable = false, .cookie = 0x0101};
352   sendEventToNanoapp(appId, SCAN_MONITOR_REQUEST, disableRequest);
353   waitForEvent(SCAN_MONITOR_REQUEST, &success);
354   EXPECT_TRUE(success);
355 
356   waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT, &cookie);
357   EXPECT_EQ(cookie, disableRequest.cookie);
358   EXPECT_FALSE(chrePalWifiIsScanMonitoringActive());
359 
360   unloadNanoapp(appId);
361 }
362 
TEST_F(WifiTimeoutTestBase,WifiRequestRangingTimeoutTest)363 TEST_F(WifiTimeoutTestBase, WifiRequestRangingTimeoutTest) {
364   CREATE_CHRE_TEST_EVENT(RANGING_REQUEST, 0);
365 
366   class App : public TestNanoapp {
367    public:
368     App()
369         : TestNanoapp(
370               TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_WIFI}) {}
371 
372     bool start() override {
373       mRequestTimer = CHRE_TIMER_INVALID;
374       return true;
375     }
376 
377     void handleEvent(uint32_t, uint16_t eventType,
378                      const void *eventData) override {
379       switch (eventType) {
380         case CHRE_EVENT_WIFI_ASYNC_RESULT: {
381           if (mRequestTimer != CHRE_TIMER_INVALID) {
382             chreTimerCancel(mRequestTimer);
383             mRequestTimer = CHRE_TIMER_INVALID;
384           }
385 
386           auto *event = static_cast<const chreAsyncResult *>(eventData);
387           if (event->success) {
388             if (event->errorCode == 0) {
389               TestEventQueueSingleton::get()->pushEvent(
390                   CHRE_EVENT_WIFI_ASYNC_RESULT,
391                   *(static_cast<const uint32_t *>(event->cookie)));
392             }
393           }
394           break;
395         }
396 
397         case CHRE_EVENT_TIMER: {
398           mRequestTimer = CHRE_TIMER_INVALID;
399           TestEventQueueSingleton::get()->pushEvent(REQUEST_TIMED_OUT);
400           break;
401         }
402 
403         case CHRE_EVENT_TEST_EVENT: {
404           auto event = static_cast<const TestEvent *>(eventData);
405           switch (event->type) {
406             case RANGING_REQUEST:
407               bool success = false;
408               mCookie = *static_cast<uint32_t *>(event->data);
409 
410               // Placeholder parameters since linux PAL does not use this to
411               // generate response
412               struct chreWifiRangingTarget dummyRangingTarget = {
413                   .macAddress = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc},
414                   .primaryChannel = 0xdef02468,
415                   .centerFreqPrimary = 0xace13579,
416                   .centerFreqSecondary = 0xbdf369cf,
417                   .channelWidth = 0x48,
418               };
419 
420               struct chreWifiRangingParams dummyRangingParams = {
421                   .targetListLen = 1,
422                   .targetList = &dummyRangingTarget,
423               };
424 
425               if (chreWifiRequestRangingAsync(&dummyRangingParams, &mCookie)) {
426                 mRequestTimer =
427                     chreTimerSet(CHRE_TEST_WIFI_RANGING_RESULT_TIMEOUT_NS,
428                                  nullptr, true /* oneShot */);
429                 success = mRequestTimer != CHRE_TIMER_INVALID;
430               }
431               TestEventQueueSingleton::get()->pushEvent(RANGING_REQUEST,
432                                                         success);
433           }
434         }
435       }
436     }
437 
438    protected:
439     uint32_t mCookie;
440     uint32_t mRequestTimer;
441   };
442 
443   uint64_t appId = loadNanoapp(MakeUnique<App>());
444 
445   uint32_t timeOutCookie = 0xdead;
446 
447   chrePalWifiEnableResponse(PalWifiAsyncRequestTypes::RANGING, false);
448   sendEventToNanoapp(appId, RANGING_REQUEST, timeOutCookie);
449   bool success;
450   waitForEvent(RANGING_REQUEST, &success);
451   EXPECT_TRUE(success);
452 
453   waitForEvent(REQUEST_TIMED_OUT);
454 
455   // Make sure that we can still request ranging after a timedout request
456   uint32_t successCookie = 0x0101;
457   chrePalWifiEnableResponse(PalWifiAsyncRequestTypes::RANGING, true);
458   sendEventToNanoapp(appId, RANGING_REQUEST, successCookie);
459   waitForEvent(RANGING_REQUEST, &success);
460   EXPECT_TRUE(success);
461 
462   uint32_t cookie;
463   waitForEvent(CHRE_EVENT_WIFI_ASYNC_RESULT, &cookie);
464   EXPECT_EQ(cookie, successCookie);
465 
466   unloadNanoapp(appId);
467 }
468 
469 }  // namespace
470 }  // namespace chre
471