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