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