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