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