xref: /aosp_15_r20/system/chre/test/simulation/gnss_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 "chre_api/chre/gnss.h"
18 
19 #include <cstdint>
20 #include <functional>
21 
22 #include "chre/core/event_loop_manager.h"
23 #include "chre/core/settings.h"
24 #include "chre/platform/linux/pal_gnss.h"
25 #include "chre/platform/log.h"
26 #include "chre/util/system/napp_permissions.h"
27 #include "chre_api/chre/event.h"
28 #include "gtest/gtest.h"
29 #include "inc/test_util.h"
30 #include "test_base.h"
31 #include "test_event.h"
32 #include "test_event_queue.h"
33 #include "test_util.h"
34 
35 namespace chre {
36 namespace {
37 
38 /**
39  * Wait for the predicate to become true with a timeout.
40  *
41  * @return the last value of the predicate.
42  */
waitForCondition(const std::function<bool ()> & predicate,std::chrono::milliseconds timeout)43 bool waitForCondition(const std::function<bool()> &predicate,
44                       std::chrono::milliseconds timeout) {
45   constexpr std::chrono::milliseconds kSleepDuration(100);
46   bool result;
47   std::chrono::milliseconds time;
48   while (!(result = predicate()) && time < timeout) {
49     std::this_thread::sleep_for(kSleepDuration);
50     time += kSleepDuration;
51   }
52   return result;
53 }
54 
55 // ref b/228669574
TEST_F(TestBase,GnssSubscriptionWithSettingChange)56 TEST_F(TestBase, GnssSubscriptionWithSettingChange) {
57   CREATE_CHRE_TEST_EVENT(LOCATION_REQUEST, 0);
58 
59   struct LocationRequest {
60     bool enable;
61     uint32_t cookie;
62   };
63 
64   class App : public TestNanoapp {
65    public:
66     App()
67         : TestNanoapp(
68               TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_GNSS}) {}
69 
70     bool start() override {
71       chreUserSettingConfigureEvents(CHRE_USER_SETTING_LOCATION,
72                                      true /*enabled*/);
73       return true;
74     }
75 
76     void handleEvent(uint32_t, uint16_t eventType,
77                      const void *eventData) override {
78       switch (eventType) {
79         case CHRE_EVENT_GNSS_ASYNC_RESULT: {
80           auto *event = static_cast<const chreAsyncResult *>(eventData);
81           if (event->success) {
82             TestEventQueueSingleton::get()->pushEvent(
83                 CHRE_EVENT_GNSS_ASYNC_RESULT,
84                 *(static_cast<const uint32_t *>(event->cookie)));
85           }
86           break;
87         }
88 
89         case CHRE_EVENT_SETTING_CHANGED_LOCATION: {
90           TestEventQueueSingleton::get()->pushEvent(
91               CHRE_EVENT_SETTING_CHANGED_LOCATION);
92           break;
93         }
94 
95         case CHRE_EVENT_TEST_EVENT: {
96           auto event = static_cast<const TestEvent *>(eventData);
97           switch (event->type) {
98             case LOCATION_REQUEST: {
99               auto request = static_cast<const LocationRequest *>(event->data);
100               bool success;
101               mCookie = request->cookie;
102               if (request->enable) {
103                 success = chreGnssLocationSessionStartAsync(
104                     1000 /*minIntervalMs*/, 1000 /*minTimeToNextFixMs*/,
105                     &mCookie);
106               } else {
107                 success = chreGnssLocationSessionStopAsync(&mCookie);
108               }
109               TestEventQueueSingleton::get()->pushEvent(LOCATION_REQUEST,
110                                                         success);
111               break;
112             }
113           }
114         }
115       }
116     }
117 
118     void end() override {
119       chreUserSettingConfigureEvents(CHRE_USER_SETTING_LOCATION,
120                                      false /*enabled*/);
121     }
122 
123    protected:
124     uint32_t mCookie;
125   };
126 
127   uint64_t appId = loadNanoapp(MakeUnique<App>());
128 
129   bool success;
130   EXPECT_FALSE(chrePalGnssIsLocationEnabled());
131   chrePalGnssDelaySendingLocationEvents(true);
132 
133   LocationRequest request{.enable = true, .cookie = 0x123};
134   sendEventToNanoapp(appId, LOCATION_REQUEST, request);
135   waitForEvent(LOCATION_REQUEST, &success);
136   EXPECT_TRUE(success);
137   chrePalGnssStartSendingLocationEvents();
138   uint32_t cookie;
139   waitForEvent(CHRE_EVENT_GNSS_ASYNC_RESULT, &cookie);
140   EXPECT_EQ(cookie, request.cookie);
141   EXPECT_TRUE(chrePalGnssIsLocationEnabled());
142 
143   EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
144       Setting::LOCATION, false /* enabled */);
145 
146   waitForEvent(CHRE_EVENT_SETTING_CHANGED_LOCATION);
147 
148   // Wait for the setting change to propagate to GNSS.
149   EXPECT_TRUE(waitForCondition([]() { return !chrePalGnssIsLocationEnabled(); },
150                                std::chrono::milliseconds(1000)));
151 
152   EventLoopManagerSingleton::get()->getSettingManager().postSettingChange(
153       Setting::LOCATION, true /* enabled */);
154 
155   waitForEvent(CHRE_EVENT_SETTING_CHANGED_LOCATION);
156 
157   // Wait for the setting change to propagate to GNSS.
158   EXPECT_TRUE(waitForCondition([]() { return chrePalGnssIsLocationEnabled(); },
159                                std::chrono::milliseconds(1000)));
160 
161   request.enable = false;
162   sendEventToNanoapp(appId, LOCATION_REQUEST, request);
163   waitForEvent(LOCATION_REQUEST, &success);
164   EXPECT_TRUE(success);
165   chrePalGnssStartSendingLocationEvents();
166   waitForEvent(CHRE_EVENT_GNSS_ASYNC_RESULT, &cookie);
167   EXPECT_EQ(cookie, request.cookie);
168   EXPECT_FALSE(chrePalGnssIsLocationEnabled());
169   chrePalGnssDelaySendingLocationEvents(false);
170 }
171 
TEST_F(TestBase,GnssCanSubscribeAndUnsubscribeToLocation)172 TEST_F(TestBase, GnssCanSubscribeAndUnsubscribeToLocation) {
173   CREATE_CHRE_TEST_EVENT(LOCATION_REQUEST, 0);
174 
175   struct LocationRequest {
176     bool enable;
177     uint32_t cookie;
178   };
179 
180   class App : public TestNanoapp {
181    public:
182     App()
183         : TestNanoapp(
184               TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_GNSS}) {}
185 
186     void handleEvent(uint32_t, uint16_t eventType,
187                      const void *eventData) override {
188       switch (eventType) {
189         case CHRE_EVENT_GNSS_ASYNC_RESULT: {
190           auto *event = static_cast<const chreAsyncResult *>(eventData);
191           if (event->success) {
192             TestEventQueueSingleton::get()->pushEvent(
193                 CHRE_EVENT_GNSS_ASYNC_RESULT,
194                 *(static_cast<const uint32_t *>(event->cookie)));
195           }
196           break;
197         }
198 
199         case CHRE_EVENT_TEST_EVENT: {
200           auto event = static_cast<const TestEvent *>(eventData);
201           switch (event->type) {
202             case LOCATION_REQUEST: {
203               auto request = static_cast<const LocationRequest *>(event->data);
204               bool success;
205               mCookie = request->cookie;
206               if (request->enable) {
207                 success = chreGnssLocationSessionStartAsync(
208                     1000 /*minIntervalMs*/, 1000 /*minTimeToNextFixMs*/,
209                     &mCookie);
210               } else {
211                 success = chreGnssLocationSessionStopAsync(&mCookie);
212               }
213               TestEventQueueSingleton::get()->pushEvent(LOCATION_REQUEST,
214                                                         success);
215               break;
216             }
217           }
218         }
219       }
220     }
221 
222    protected:
223     uint32_t mCookie;
224   };
225 
226   uint64_t appId = loadNanoapp(MakeUnique<App>());
227 
228   bool success;
229   EXPECT_FALSE(chrePalGnssIsLocationEnabled());
230 
231   LocationRequest request{.enable = true, .cookie = 0x123};
232   sendEventToNanoapp(appId, LOCATION_REQUEST, request);
233   waitForEvent(LOCATION_REQUEST, &success);
234   EXPECT_TRUE(success);
235   uint32_t cookie;
236   waitForEvent(CHRE_EVENT_GNSS_ASYNC_RESULT, &cookie);
237   EXPECT_EQ(cookie, request.cookie);
238   EXPECT_TRUE(chrePalGnssIsLocationEnabled());
239 
240   request.enable = false;
241   sendEventToNanoapp(appId, LOCATION_REQUEST, request);
242   waitForEvent(LOCATION_REQUEST, &success);
243   EXPECT_TRUE(success);
244   waitForEvent(CHRE_EVENT_GNSS_ASYNC_RESULT, &cookie);
245   EXPECT_EQ(cookie, request.cookie);
246   EXPECT_FALSE(chrePalGnssIsLocationEnabled());
247 }
248 
TEST_F(TestBase,GnssUnsubscribeToLocationOnUnload)249 TEST_F(TestBase, GnssUnsubscribeToLocationOnUnload) {
250   CREATE_CHRE_TEST_EVENT(LOCATION_REQUEST, 0);
251 
252   struct LocationRequest {
253     bool enable;
254     uint32_t cookie;
255   };
256 
257   class App : public TestNanoapp {
258    public:
259     App()
260         : TestNanoapp(
261               TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_GNSS}) {}
262 
263     void handleEvent(uint32_t, uint16_t eventType,
264                      const void *eventData) override {
265       switch (eventType) {
266         case CHRE_EVENT_GNSS_ASYNC_RESULT: {
267           auto *event = static_cast<const chreAsyncResult *>(eventData);
268           if (event->success) {
269             TestEventQueueSingleton::get()->pushEvent(
270                 CHRE_EVENT_GNSS_ASYNC_RESULT,
271                 *(static_cast<const uint32_t *>(event->cookie)));
272           }
273           break;
274         }
275 
276         case CHRE_EVENT_TEST_EVENT: {
277           auto event = static_cast<const TestEvent *>(eventData);
278           switch (event->type) {
279             case LOCATION_REQUEST: {
280               auto request = static_cast<const LocationRequest *>(event->data);
281               if (request->enable) {
282                 mCookie = request->cookie;
283                 const bool success = chreGnssLocationSessionStartAsync(
284                     1000 /*minIntervalMs*/, 1000 /*minTimeToNextFixMs*/,
285                     &mCookie);
286                 TestEventQueueSingleton::get()->pushEvent(LOCATION_REQUEST,
287                                                           success);
288               }
289               break;
290             }
291           }
292         }
293       }
294     }
295 
296    protected:
297     uint32_t mCookie;
298   };
299 
300   uint64_t appId = loadNanoapp(MakeUnique<App>());
301 
302   EXPECT_FALSE(chrePalGnssIsLocationEnabled());
303 
304   LocationRequest request{.enable = true, .cookie = 0x123};
305   sendEventToNanoapp(appId, LOCATION_REQUEST, request);
306   bool success;
307   waitForEvent(LOCATION_REQUEST, &success);
308   EXPECT_TRUE(success);
309   uint32_t cookie;
310   waitForEvent(CHRE_EVENT_GNSS_ASYNC_RESULT, &cookie);
311   EXPECT_EQ(cookie, request.cookie);
312   EXPECT_TRUE(chrePalGnssIsLocationEnabled());
313 
314   unloadNanoapp(appId);
315   EXPECT_FALSE(chrePalGnssIsLocationEnabled());
316 }
317 
TEST_F(TestBase,GnssCanSubscribeAndUnsubscribeToMeasurement)318 TEST_F(TestBase, GnssCanSubscribeAndUnsubscribeToMeasurement) {
319   CREATE_CHRE_TEST_EVENT(MEASUREMENT_REQUEST, 0);
320 
321   struct MeasurementRequest {
322     bool enable;
323     uint32_t cookie;
324   };
325 
326   class App : public TestNanoapp {
327    public:
328     App()
329         : TestNanoapp(
330               TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_GNSS}) {}
331 
332     void handleEvent(uint32_t, uint16_t eventType,
333                      const void *eventData) override {
334       static uint32_t cookie;
335       switch (eventType) {
336         case CHRE_EVENT_GNSS_ASYNC_RESULT: {
337           auto *event = static_cast<const chreAsyncResult *>(eventData);
338           if (event->success) {
339             TestEventQueueSingleton::get()->pushEvent(
340                 CHRE_EVENT_GNSS_ASYNC_RESULT,
341                 *(static_cast<const uint32_t *>(event->cookie)));
342           }
343           break;
344         }
345 
346         case CHRE_EVENT_TEST_EVENT: {
347           auto event = static_cast<const TestEvent *>(eventData);
348           switch (event->type) {
349             case MEASUREMENT_REQUEST: {
350               auto request =
351                   static_cast<const MeasurementRequest *>(event->data);
352               bool success;
353               mCookie = request->cookie;
354               if (request->enable) {
355                 success = chreGnssMeasurementSessionStartAsync(
356                     1000 /*minIntervalMs*/, &mCookie);
357               } else {
358                 cookie = request->cookie;
359                 success = chreGnssMeasurementSessionStopAsync(&mCookie);
360               }
361               TestEventQueueSingleton::get()->pushEvent(MEASUREMENT_REQUEST,
362                                                         success);
363               break;
364             }
365           }
366         }
367       }
368     }
369 
370    protected:
371     uint32_t mCookie;
372   };
373 
374   uint64_t appId = loadNanoapp(MakeUnique<App>());
375 
376   bool success;
377   EXPECT_FALSE(chrePalGnssIsLocationEnabled());
378 
379   MeasurementRequest request{.enable = true, .cookie = 0x123};
380   sendEventToNanoapp(appId, MEASUREMENT_REQUEST, request);
381   waitForEvent(MEASUREMENT_REQUEST, &success);
382   EXPECT_TRUE(success);
383   uint32_t cookie;
384   waitForEvent(CHRE_EVENT_GNSS_ASYNC_RESULT, &cookie);
385   EXPECT_EQ(cookie, request.cookie);
386   EXPECT_TRUE(chrePalGnssIsMeasurementEnabled());
387 
388   request.enable = false;
389   sendEventToNanoapp(appId, MEASUREMENT_REQUEST, request);
390   waitForEvent(MEASUREMENT_REQUEST, &success);
391   EXPECT_TRUE(success);
392   waitForEvent(CHRE_EVENT_GNSS_ASYNC_RESULT, &cookie);
393   EXPECT_EQ(cookie, request.cookie);
394   EXPECT_FALSE(chrePalGnssIsMeasurementEnabled());
395 }
396 
TEST_F(TestBase,GnssUnsubscribeToMeasurementOnUnload)397 TEST_F(TestBase, GnssUnsubscribeToMeasurementOnUnload) {
398   CREATE_CHRE_TEST_EVENT(MEASUREMENT_REQUEST, 0);
399 
400   struct MeasurementRequest {
401     bool enable;
402     uint32_t cookie;
403   };
404 
405   class App : public TestNanoapp {
406    public:
407     App()
408         : TestNanoapp(
409               TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_GNSS}) {}
410 
411     void handleEvent(uint32_t, uint16_t eventType,
412                      const void *eventData) override {
413       switch (eventType) {
414         case CHRE_EVENT_GNSS_ASYNC_RESULT: {
415           auto *event = static_cast<const chreAsyncResult *>(eventData);
416           if (event->success) {
417             TestEventQueueSingleton::get()->pushEvent(
418                 CHRE_EVENT_GNSS_ASYNC_RESULT,
419                 *(static_cast<const uint32_t *>(event->cookie)));
420           }
421           break;
422         }
423 
424         case CHRE_EVENT_TEST_EVENT: {
425           auto event = static_cast<const TestEvent *>(eventData);
426           switch (event->type) {
427             case MEASUREMENT_REQUEST: {
428               auto request =
429                   static_cast<const MeasurementRequest *>(event->data);
430               if (request->enable) {
431                 mCookie = request->cookie;
432                 const bool success = chreGnssMeasurementSessionStartAsync(
433                     1000 /*minIntervalMs*/, &mCookie);
434                 TestEventQueueSingleton::get()->pushEvent(MEASUREMENT_REQUEST,
435                                                           success);
436               }
437               break;
438             }
439           }
440         }
441       }
442     }
443 
444    protected:
445     uint32_t mCookie;
446   };
447 
448   uint64_t appId = loadNanoapp(MakeUnique<App>());
449 
450   EXPECT_FALSE(chrePalGnssIsLocationEnabled());
451 
452   MeasurementRequest request{.enable = true, .cookie = 0x123};
453   sendEventToNanoapp(appId, MEASUREMENT_REQUEST, request);
454   bool success;
455   waitForEvent(MEASUREMENT_REQUEST, &success);
456   EXPECT_TRUE(success);
457   uint32_t cookie;
458   waitForEvent(CHRE_EVENT_GNSS_ASYNC_RESULT, &cookie);
459   EXPECT_EQ(cookie, request.cookie);
460   EXPECT_TRUE(chrePalGnssIsMeasurementEnabled());
461 
462   unloadNanoapp(appId);
463   EXPECT_FALSE(chrePalGnssIsMeasurementEnabled());
464 }
465 
TEST_F(TestBase,GnssCanSubscribeAndUnsubscribeToPassiveListener)466 TEST_F(TestBase, GnssCanSubscribeAndUnsubscribeToPassiveListener) {
467   CREATE_CHRE_TEST_EVENT(LISTENER_REQUEST, 0);
468 
469   class App : public TestNanoapp {
470    public:
471     App()
472         : TestNanoapp(
473               TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_GNSS}) {}
474 
475     void handleEvent(uint32_t, uint16_t eventType,
476                      const void *eventData) override {
477       switch (eventType) {
478         case CHRE_EVENT_TEST_EVENT: {
479           auto event = static_cast<const TestEvent *>(eventData);
480           switch (event->type) {
481             case LISTENER_REQUEST: {
482               auto enable = *(static_cast<const bool *>(event->data));
483               const bool success =
484                   chreGnssConfigurePassiveLocationListener(enable);
485               TestEventQueueSingleton::get()->pushEvent(LISTENER_REQUEST,
486                                                         success);
487               break;
488             }
489           }
490         }
491       }
492     }
493   };
494 
495   uint64_t appId = loadNanoapp(MakeUnique<App>());
496 
497   bool success;
498   EXPECT_FALSE(chrePalGnssIsPassiveLocationListenerEnabled());
499 
500   sendEventToNanoapp(appId, LISTENER_REQUEST, true);
501   waitForEvent(LISTENER_REQUEST, &success);
502   EXPECT_TRUE(success);
503   EXPECT_TRUE(chrePalGnssIsPassiveLocationListenerEnabled());
504 
505   sendEventToNanoapp(appId, LISTENER_REQUEST, false);
506   waitForEvent(LISTENER_REQUEST, &success);
507   EXPECT_TRUE(success);
508   EXPECT_FALSE(chrePalGnssIsPassiveLocationListenerEnabled());
509 }
510 
TEST_F(TestBase,GnssUnsubscribeToPassiveListenerOnUnload)511 TEST_F(TestBase, GnssUnsubscribeToPassiveListenerOnUnload) {
512   CREATE_CHRE_TEST_EVENT(LISTENER_REQUEST, 0);
513 
514   class App : public TestNanoapp {
515    public:
516     App()
517         : TestNanoapp(
518               TestNanoappInfo{.perms = NanoappPermissions::CHRE_PERMS_GNSS}) {}
519 
520     void handleEvent(uint32_t, uint16_t eventType,
521                      const void *eventData) override {
522       switch (eventType) {
523         case CHRE_EVENT_TEST_EVENT: {
524           auto event = static_cast<const TestEvent *>(eventData);
525           switch (event->type) {
526             case LISTENER_REQUEST: {
527               auto enable = *(static_cast<const bool *>(event->data));
528               const bool success =
529                   chreGnssConfigurePassiveLocationListener(enable);
530               TestEventQueueSingleton::get()->pushEvent(LISTENER_REQUEST,
531                                                         success);
532             }
533           }
534         }
535       }
536     }
537   };
538 
539   uint64_t appId = loadNanoapp(MakeUnique<App>());
540 
541   EXPECT_FALSE(chrePalGnssIsPassiveLocationListenerEnabled());
542 
543   sendEventToNanoapp(appId, LISTENER_REQUEST, true);
544   bool success;
545   waitForEvent(LISTENER_REQUEST, &success);
546   EXPECT_TRUE(success);
547   EXPECT_TRUE(chrePalGnssIsPassiveLocationListenerEnabled());
548 
549   unloadNanoapp(appId);
550   EXPECT_FALSE(chrePalGnssIsPassiveLocationListenerEnabled());
551 }
552 
553 }  // namespace
554 }  // namespace chre