1 /*
2  * Copyright (C) 2020 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 "chpp/services/gnss.h"
18 
19 #include <inttypes.h>
20 #include <stddef.h>
21 #include <stdint.h>
22 
23 #include "chpp/common/gnss.h"
24 #include "chpp/common/gnss_types.h"
25 #include "chpp/common/standard_uuids.h"
26 #include "chpp/log.h"
27 #include "chpp/macros.h"
28 #include "chpp/services.h"
29 #include "chre/pal/gnss.h"
30 
31 /************************************************
32  *  Prototypes
33  ***********************************************/
34 
35 static enum ChppAppErrorCode chppDispatchGnssRequest(void *serviceContext,
36                                                      uint8_t *buf, size_t len);
37 static void chppGnssServiceNotifyReset(void *serviceContext);
38 
39 /************************************************
40  *  Private Definitions
41  ***********************************************/
42 
43 /**
44  * Configuration parameters for this service
45  */
46 static const struct ChppService kGnssServiceConfig = {
47     .descriptor.uuid = CHPP_UUID_GNSS_STANDARD,
48 
49     // Human-readable name
50     .descriptor.name = "GNSS",
51 
52     // Version
53     .descriptor.version.major = 1,
54     .descriptor.version.minor = 0,
55     .descriptor.version.patch = 0,
56 
57     // Notifies service if CHPP is reset
58     .resetNotifierFunctionPtr = &chppGnssServiceNotifyReset,
59 
60     // Client request dispatch function pointer
61     .requestDispatchFunctionPtr = &chppDispatchGnssRequest,
62 
63     // Client notification dispatch function pointer
64     .notificationDispatchFunctionPtr = NULL,  // Not supported
65 
66     // Min length is the entire header
67     .minLength = sizeof(struct ChppAppHeader),
68 };
69 
70 /**
71  * Structure to maintain state for the GNSS service and its Request/Response
72  * (RR) functionality.
73  */
74 struct ChppGnssServiceState {
75   struct ChppEndpointState service;  // CHPP service state
76   const struct chrePalGnssApi *api;  // GNSS PAL API
77 
78   // Based on chre/pal/gnss.h and chrePalGnssApi
79   struct ChppIncomingRequestState open;             // Service init state
80   struct ChppIncomingRequestState close;            // Service deinit state
81   struct ChppIncomingRequestState getCapabilities;  // Get Capabilities state
82   struct ChppIncomingRequestState
83       controlLocationSession;  // Control Location measurement state
84   struct ChppIncomingRequestState
85       controlMeasurementSession;  // Control Raw GNSS measurement state
86   struct ChppIncomingRequestState
87       configurePassiveLocationListener;  // Configure Passive location receiving
88                                          // state
89 };
90 
91 // Note: The CHRE PAL API only allows for one definition - see comment in WWAN
92 // service for details.
93 // Note: There is no notion of a cookie in the CHRE GNSS API so we need to use
94 // the global service state (gGnssServiceContext) directly in all callbacks.
95 struct ChppGnssServiceState gGnssServiceContext;
96 
97 /************************************************
98  *  Prototypes
99  ***********************************************/
100 
101 static enum ChppAppErrorCode chppGnssServiceOpen(
102     struct ChppGnssServiceState *gnssServiceContext,
103     struct ChppAppHeader *requestHeader);
104 static enum ChppAppErrorCode chppGnssServiceClose(
105     struct ChppGnssServiceState *gnssServiceContext,
106     struct ChppAppHeader *requestHeader);
107 static enum ChppAppErrorCode chppGnssServiceGetCapabilities(
108     struct ChppGnssServiceState *gnssServiceContext,
109     struct ChppAppHeader *requestHeader);
110 static enum ChppAppErrorCode chppGnssServiceControlLocationSession(
111     struct ChppGnssServiceState *gnssServiceContext,
112     struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len);
113 static enum ChppAppErrorCode chppGnssServiceControlMeasurementSession(
114     struct ChppGnssServiceState *gnssServiceContext,
115     struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len);
116 static enum ChppAppErrorCode chppGnssServiceConfigurePassiveLocationListener(
117     struct ChppGnssServiceState *gnssServiceContext,
118     struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len);
119 
120 static void chppGnssServiceRequestStateResyncCallback(void);
121 static void chppGnssServiceLocationStatusChangeCallback(bool enabled,
122                                                         uint8_t errorCode);
123 static void chppGnssServiceLocationEventCallback(
124     struct chreGnssLocationEvent *event);
125 static void chppGnssServiceMeasurementStatusChangeCallback(bool enabled,
126                                                            uint8_t errorCode);
127 static void chppGnssServiceMeasurementEventCallback(
128     struct chreGnssDataEvent *event);
129 
130 /************************************************
131  *  Private Functions
132  ***********************************************/
133 
134 /**
135  * Dispatches a client request from the transport layer that is determined to be
136  * for the GNSS service. If the result of the dispatch is an error, this
137  * function responds to the client with the same error.
138  *
139  * This function is called from the app layer using its function pointer given
140  * during service registration.
141  *
142  * @param serviceContext Maintains status for each service instance.
143  * @param buf Input data. Cannot be null.
144  * @param len Length of input data in bytes.
145  *
146  * @return Indicates the result of this function call.
147  */
chppDispatchGnssRequest(void * serviceContext,uint8_t * buf,size_t len)148 static enum ChppAppErrorCode chppDispatchGnssRequest(void *serviceContext,
149                                                      uint8_t *buf, size_t len) {
150   struct ChppAppHeader *rxHeader = (struct ChppAppHeader *)buf;
151   buf += sizeof(struct ChppAppHeader);
152   len -= sizeof(struct ChppAppHeader);
153 
154   struct ChppGnssServiceState *gnssServiceContext =
155       (struct ChppGnssServiceState *)serviceContext;
156   struct ChppIncomingRequestState *inReqState = NULL;
157   enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
158   bool dispatched = true;
159 
160   switch (rxHeader->command) {
161     case CHPP_GNSS_OPEN: {
162       inReqState = &gnssServiceContext->open;
163       chppTimestampIncomingRequest(inReqState, rxHeader);
164       error = chppGnssServiceOpen(gnssServiceContext, rxHeader);
165       break;
166     }
167 
168     case CHPP_GNSS_CLOSE: {
169       inReqState = &gnssServiceContext->close;
170       chppTimestampIncomingRequest(inReqState, rxHeader);
171       error = chppGnssServiceClose(gnssServiceContext, rxHeader);
172       break;
173     }
174 
175     case CHPP_GNSS_GET_CAPABILITIES: {
176       inReqState = &gnssServiceContext->getCapabilities;
177       chppTimestampIncomingRequest(inReqState, rxHeader);
178       error = chppGnssServiceGetCapabilities(gnssServiceContext, rxHeader);
179       break;
180     }
181 
182     case CHPP_GNSS_CONTROL_LOCATION_SESSION: {
183       inReqState = &gnssServiceContext->controlLocationSession;
184       chppTimestampIncomingRequest(inReqState, rxHeader);
185       error = chppGnssServiceControlLocationSession(gnssServiceContext,
186                                                     rxHeader, buf, len);
187       break;
188     }
189 
190     case CHPP_GNSS_CONTROL_MEASUREMENT_SESSION: {
191       inReqState = &gnssServiceContext->controlMeasurementSession;
192       chppTimestampIncomingRequest(inReqState, rxHeader);
193       error = chppGnssServiceControlMeasurementSession(gnssServiceContext,
194                                                        rxHeader, buf, len);
195       break;
196     }
197 
198     case CHPP_GNSS_CONFIGURE_PASSIVE_LOCATION_LISTENER: {
199       inReqState = &gnssServiceContext->configurePassiveLocationListener;
200       chppTimestampIncomingRequest(inReqState, rxHeader);
201       error = chppGnssServiceConfigurePassiveLocationListener(
202           gnssServiceContext, rxHeader, buf, len);
203       break;
204     }
205 
206     default: {
207       dispatched = false;
208       error = CHPP_APP_ERROR_INVALID_COMMAND;
209       break;
210     }
211   }
212 
213   if (dispatched == true && error != CHPP_APP_ERROR_NONE) {
214     // Request was dispatched but an error was returned. Close out
215     // chppTimestampIncomingRequest()
216     chppTimestampOutgoingResponse(inReqState);
217   }
218 
219   return error;
220 }
221 
222 /**
223  * Initializes the GNSS service upon an open request from the client and
224  * responds to the client with the result.
225  *
226  * @param serviceContext Maintains status for each service instance.
227  * @param requestHeader App layer header of the request.
228  *
229  * @return Indicates the result of this function call.
230  */
chppGnssServiceOpen(struct ChppGnssServiceState * gnssServiceContext,struct ChppAppHeader * requestHeader)231 static enum ChppAppErrorCode chppGnssServiceOpen(
232     struct ChppGnssServiceState *gnssServiceContext,
233     struct ChppAppHeader *requestHeader) {
234   static const struct chrePalGnssCallbacks palCallbacks = {
235       .requestStateResync = chppGnssServiceRequestStateResyncCallback,
236       .locationStatusChangeCallback =
237           chppGnssServiceLocationStatusChangeCallback,
238       .locationEventCallback = chppGnssServiceLocationEventCallback,
239       .measurementStatusChangeCallback =
240           chppGnssServiceMeasurementStatusChangeCallback,
241       .measurementEventCallback = chppGnssServiceMeasurementEventCallback,
242   };
243 
244   enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
245 
246   if (gnssServiceContext->service.openState == CHPP_OPEN_STATE_OPENED) {
247     CHPP_DEBUG_ASSERT_LOG(false, "GNSS service already open");
248     error = CHPP_APP_ERROR_INVALID_COMMAND;
249 
250   } else if (!gnssServiceContext->api->open(
251                  gnssServiceContext->service.appContext->systemApi,
252                  &palCallbacks)) {
253     CHPP_DEBUG_ASSERT_LOG(false, "GNSS PAL open failed");
254     error = CHPP_APP_ERROR_BEYOND_CHPP;
255 
256   } else {
257     CHPP_LOGD("GNSS service opened");
258     gnssServiceContext->service.openState = CHPP_OPEN_STATE_OPENED;
259 
260     struct ChppAppHeader *response =
261         chppAllocResponseFixed(requestHeader, struct ChppAppHeader);
262     size_t responseLen = sizeof(*response);
263 
264     if (response == NULL) {
265       CHPP_LOG_OOM();
266       error = CHPP_APP_ERROR_OOM;
267     } else {
268       chppSendTimestampedResponseOrFail(gnssServiceContext->service.appContext,
269                                         &gnssServiceContext->open, response,
270                                         responseLen);
271     }
272   }
273 
274   return error;
275 }
276 
277 /**
278  * Deinitializes the GNSS service.
279  *
280  * @param serviceContext Maintains status for each service instance.
281  * @param requestHeader App layer header of the request.
282  *
283  * @return Indicates the result of this function call.
284  */
chppGnssServiceClose(struct ChppGnssServiceState * gnssServiceContext,struct ChppAppHeader * requestHeader)285 static enum ChppAppErrorCode chppGnssServiceClose(
286     struct ChppGnssServiceState *gnssServiceContext,
287     struct ChppAppHeader *requestHeader) {
288   enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
289 
290   gnssServiceContext->api->close();
291   gnssServiceContext->service.openState = CHPP_OPEN_STATE_CLOSED;
292 
293   CHPP_LOGD("GNSS service closed");
294 
295   struct ChppAppHeader *response =
296       chppAllocResponseFixed(requestHeader, struct ChppAppHeader);
297   size_t responseLen = sizeof(*response);
298 
299   if (response == NULL) {
300     CHPP_LOG_OOM();
301     error = CHPP_APP_ERROR_OOM;
302   } else {
303     chppSendTimestampedResponseOrFail(gnssServiceContext->service.appContext,
304                                       &gnssServiceContext->close, response,
305                                       responseLen);
306   }
307 
308   return error;
309 }
310 
311 /**
312  * Notifies the service of an incoming reset.
313  *
314  * @param serviceContext Maintains status for each service instance.
315  */
chppGnssServiceNotifyReset(void * serviceContext)316 static void chppGnssServiceNotifyReset(void *serviceContext) {
317   struct ChppGnssServiceState *gnssServiceContext =
318       (struct ChppGnssServiceState *)serviceContext;
319 
320   if (gnssServiceContext->service.openState != CHPP_OPEN_STATE_OPENED) {
321     CHPP_LOGW("GNSS service reset but wasn't open");
322   } else {
323     CHPP_LOGD("GNSS service reset. Closing");
324     gnssServiceContext->service.openState = CHPP_OPEN_STATE_CLOSED;
325     gnssServiceContext->api->close();
326   }
327 }
328 
329 /**
330  * Retrieves a set of flags indicating the GNSS features supported by the
331  * current implementation.
332  *
333  * @param serviceContext Maintains status for each service instance.
334  * @param requestHeader App layer header of the request.
335  *
336  * @return Indicates the result of this function call.
337  */
chppGnssServiceGetCapabilities(struct ChppGnssServiceState * gnssServiceContext,struct ChppAppHeader * requestHeader)338 static enum ChppAppErrorCode chppGnssServiceGetCapabilities(
339     struct ChppGnssServiceState *gnssServiceContext,
340     struct ChppAppHeader *requestHeader) {
341   enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
342 
343   struct ChppGnssGetCapabilitiesResponse *response = chppAllocResponseFixed(
344       requestHeader, struct ChppGnssGetCapabilitiesResponse);
345   size_t responseLen = sizeof(*response);
346 
347   if (response == NULL) {
348     CHPP_LOG_OOM();
349     error = CHPP_APP_ERROR_OOM;
350   } else {
351     response->params.capabilities = gnssServiceContext->api->getCapabilities();
352 
353     CHPP_LOGD("chppGnssServiceGetCapabilities returning 0x%" PRIx32
354               ", %" PRIuSIZE " bytes",
355               response->params.capabilities, responseLen);
356     chppSendTimestampedResponseOrFail(gnssServiceContext->service.appContext,
357                                       &gnssServiceContext->getCapabilities,
358                                       response, responseLen);
359   }
360 
361   return error;
362 }
363 
364 /**
365  * Start/stop/modify the GNSS location session.
366  *
367  * This function returns an error code synchronously.
368  * A subsequent call to chppGnssServiceLocationStatusChangeCallback() will be
369  * used to communicate the result of this request (as a service response).
370  * A subsequent call to chppGnssServiceLocationEventCallback() will be used to
371  * communicate the location fixes (as service notifications).
372  *
373  * @param serviceContext Maintains status for each service instance.
374  * @param requestHeader App layer header of the request.
375  * @param buf Input data. Cannot be null.
376  * @param len Length of input data in bytes.
377  *
378  * @return Indicates the result of this function call.
379  */
chppGnssServiceControlLocationSession(struct ChppGnssServiceState * gnssServiceContext,struct ChppAppHeader * requestHeader,uint8_t * buf,size_t len)380 static enum ChppAppErrorCode chppGnssServiceControlLocationSession(
381     struct ChppGnssServiceState *gnssServiceContext,
382     struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len) {
383   UNUSED_VAR(requestHeader);
384   enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
385 
386   if (len < sizeof(struct ChppGnssControlLocationSessionParameters)) {
387     error = CHPP_APP_ERROR_INVALID_ARG;
388 
389   } else {
390     struct ChppGnssControlLocationSessionParameters *parameters =
391         (struct ChppGnssControlLocationSessionParameters *)buf;
392 
393     if (!gnssServiceContext->api->controlLocationSession(
394             parameters->enable, parameters->minIntervalMs,
395             parameters->minTimeToNextFixMs)) {
396       error = CHPP_APP_ERROR_UNSPECIFIED;
397     }
398   }
399 
400   return error;
401 }
402 
403 /**
404  * Start/stop/modify the raw GNSS measurement session.
405  *
406  * This function returns an error code synchronously.
407  * A subsequent call to chppGnssServiceMeasurementStatusChangeCallback() will be
408  * used to communicate the result of this request (as a service response).
409  * A subsequent call to chppGnssServiceMeasurementEventCallback() will be used
410  * to communicate the measurements (as service notifications).
411  *
412  * @param serviceContext Maintains status for each service instance.
413  * @param requestHeader App layer header of the request.
414  * @param buf Input data. Cannot be null.
415  * @param len Length of input data in bytes.
416  *
417  * @return Indicates the result of this function call.
418  */
chppGnssServiceControlMeasurementSession(struct ChppGnssServiceState * gnssServiceContext,struct ChppAppHeader * requestHeader,uint8_t * buf,size_t len)419 static enum ChppAppErrorCode chppGnssServiceControlMeasurementSession(
420     struct ChppGnssServiceState *gnssServiceContext,
421     struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len) {
422   UNUSED_VAR(requestHeader);
423   enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
424 
425   if (len < sizeof(struct ChppGnssControlMeasurementSessionParameters)) {
426     error = CHPP_APP_ERROR_INVALID_ARG;
427 
428   } else {
429     struct ChppGnssControlMeasurementSessionParameters *parameters =
430         (struct ChppGnssControlMeasurementSessionParameters *)buf;
431 
432     if (!gnssServiceContext->api->controlMeasurementSession(
433             parameters->enable, parameters->minIntervalMs)) {
434       error = CHPP_APP_ERROR_UNSPECIFIED;
435     }
436   }
437 
438   return error;
439 }
440 
441 /**
442  * Configures whether to opportunistically deliver any location fixes produced
443  * for other clients of the GNSS engine.
444  *
445  * This function returns an error code synchronously.
446  * A subsequent call to chppGnssServiceLocationEventCallback() will be used to
447  * communicate the location fixes (as service notifications).
448  *
449  * @param serviceContext Maintains status for each service instance.
450  * @param requestHeader App layer header of the request.
451  * @param buf Input data. Cannot be null.
452  * @param len Length of input data in bytes.
453  *
454  * @return Indicates the result of this function call.
455  */
chppGnssServiceConfigurePassiveLocationListener(struct ChppGnssServiceState * gnssServiceContext,struct ChppAppHeader * requestHeader,uint8_t * buf,size_t len)456 static enum ChppAppErrorCode chppGnssServiceConfigurePassiveLocationListener(
457     struct ChppGnssServiceState *gnssServiceContext,
458     struct ChppAppHeader *requestHeader, uint8_t *buf, size_t len) {
459   UNUSED_VAR(requestHeader);
460   enum ChppAppErrorCode error = CHPP_APP_ERROR_NONE;
461 
462   if (len < sizeof(struct ChppGnssConfigurePassiveLocationListenerParameters)) {
463     error = CHPP_APP_ERROR_INVALID_ARG;
464   } else {
465     struct ChppGnssConfigurePassiveLocationListenerParameters *parameters =
466         (struct ChppGnssConfigurePassiveLocationListenerParameters *)buf;
467 
468     if (!gnssServiceContext->api->configurePassiveLocationListener(
469             parameters->enable)) {
470       error = CHPP_APP_ERROR_UNSPECIFIED;
471 
472     } else {
473       struct ChppAppHeader *response =
474           chppAllocResponseFixed(requestHeader, struct ChppAppHeader);
475       size_t responseLen = sizeof(*response);
476 
477       if (response == NULL) {
478         CHPP_LOG_OOM();
479         error = CHPP_APP_ERROR_OOM;
480       } else {
481         chppSendTimestampedResponseOrFail(
482             gnssServiceContext->service.appContext,
483             &gnssServiceContext->configurePassiveLocationListener, response,
484             responseLen);
485       }
486     }
487   }
488 
489   return error;
490 }
491 
492 /**
493  * GNSS PAL callback to request that the core CHRE system re-send requests for
494  * any active sessions and its current passive location listener setting.
495  */
chppGnssServiceRequestStateResyncCallback(void)496 static void chppGnssServiceRequestStateResyncCallback(void) {
497   struct ChppAppHeader *notification =
498       chppAllocServiceNotificationFixed(struct ChppAppHeader);
499   size_t notificationLen = sizeof(*notification);
500 
501   if (notification == NULL) {
502     CHPP_LOG_OOM();
503     CHPP_ASSERT(false);
504 
505   } else {
506     notification->handle = gGnssServiceContext.service.handle;
507     notification->command = CHPP_GNSS_REQUEST_STATE_RESYNC_NOTIFICATION;
508 
509     chppEnqueueTxDatagramOrFail(
510         gGnssServiceContext.service.appContext->transportContext, notification,
511         notificationLen);
512   }
513 }
514 
515 /**
516  * GNSS PAL callback to inform the CHRE of the result of changes to the location
517  * session status.
518  */
chppGnssServiceLocationStatusChangeCallback(bool enabled,uint8_t errorCode)519 static void chppGnssServiceLocationStatusChangeCallback(bool enabled,
520                                                         uint8_t errorCode) {
521   // Recreate request header
522   struct ChppAppHeader requestHeader = {
523       .handle = gGnssServiceContext.service.handle,
524       .transaction = gGnssServiceContext.controlLocationSession.transaction,
525       .command = CHPP_GNSS_CONTROL_LOCATION_SESSION,
526   };
527 
528   struct ChppGnssControlLocationSessionResponse *response =
529       chppAllocResponseFixed(&requestHeader,
530                              struct ChppGnssControlLocationSessionResponse);
531   size_t responseLen = sizeof(*response);
532 
533   if (response == NULL) {
534     CHPP_LOG_OOM();
535     CHPP_ASSERT(false);
536 
537   } else {
538     response->enabled = enabled;
539     response->errorCode = errorCode;
540 
541     chppSendTimestampedResponseOrFail(
542         gGnssServiceContext.service.appContext,
543         &gGnssServiceContext.controlLocationSession, response, responseLen);
544   }
545 }
546 
547 /**
548  * GNSS PAL callback to pass GNSS location fixes to the core CHRE system.
549  */
chppGnssServiceLocationEventCallback(struct chreGnssLocationEvent * event)550 static void chppGnssServiceLocationEventCallback(
551     struct chreGnssLocationEvent *event) {
552   // Craft response per parser script
553   struct ChppGnssLocationEventWithHeader *notification = NULL;
554   size_t notificationLen = 0;
555 
556   if (!chppGnssLocationEventFromChre(event, &notification, &notificationLen)) {
557     CHPP_LOGE("LocationEvent conversion failed (OOM?)");
558 
559     notification = chppMalloc(sizeof(struct ChppAppHeader));
560     if (notification == NULL) {
561       CHPP_LOG_OOM();
562     } else {
563       notificationLen = sizeof(struct ChppAppHeader);
564     }
565   }
566 
567   if (notification != NULL) {
568     notification->header.handle = gGnssServiceContext.service.handle;
569     notification->header.type = CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION;
570     notification->header.transaction =
571         0;  // Because we don't know this is in response to a Location Session
572             // or Passive Location Listener
573     notification->header.error =
574         (notificationLen > sizeof(struct ChppAppHeader))
575             ? CHPP_APP_ERROR_NONE
576             : CHPP_APP_ERROR_CONVERSION_FAILED;
577     notification->header.command = CHPP_GNSS_LOCATION_RESULT_NOTIFICATION;
578 
579     chppEnqueueTxDatagramOrFail(
580         gGnssServiceContext.service.appContext->transportContext, notification,
581         notificationLen);
582   }
583 
584   gGnssServiceContext.api->releaseLocationEvent(event);
585 }
586 
587 /**
588  * GNSS PAL callback to inform the CHRE of the result of changes to the raw GNSS
589  * measurement session status.
590  */
chppGnssServiceMeasurementStatusChangeCallback(bool enabled,uint8_t errorCode)591 static void chppGnssServiceMeasurementStatusChangeCallback(bool enabled,
592                                                            uint8_t errorCode) {
593   // Recreate request header
594   struct ChppAppHeader requestHeader = {
595       .handle = gGnssServiceContext.service.handle,
596       .transaction = gGnssServiceContext.controlMeasurementSession.transaction,
597       .command = CHPP_GNSS_CONTROL_MEASUREMENT_SESSION,
598   };
599 
600   struct ChppGnssControlMeasurementSessionResponse *response =
601       chppAllocResponseFixed(&requestHeader,
602                              struct ChppGnssControlMeasurementSessionResponse);
603   size_t responseLen = sizeof(*response);
604 
605   if (response == NULL) {
606     CHPP_LOG_OOM();
607     CHPP_ASSERT(false);
608 
609   } else {
610     response->enabled = enabled;
611     response->errorCode = errorCode;
612 
613     chppSendTimestampedResponseOrFail(
614         gGnssServiceContext.service.appContext,
615         &gGnssServiceContext.controlMeasurementSession, response, responseLen);
616   }
617 }
618 
619 /**
620  * GNSS PAL callback to pass raw GNSS measurement data to the core CHRE system.
621  */
chppGnssServiceMeasurementEventCallback(struct chreGnssDataEvent * event)622 static void chppGnssServiceMeasurementEventCallback(
623     struct chreGnssDataEvent *event) {
624   // Craft response per parser script
625   struct ChppGnssDataEventWithHeader *notification = NULL;
626   size_t notificationLen = 0;
627 
628   if (!chppGnssDataEventFromChre(event, &notification, &notificationLen)) {
629     CHPP_LOGE("DataEvent conversion failed (OOM?) ID=%" PRIu8,
630               gGnssServiceContext.controlMeasurementSession.transaction);
631 
632     notification = chppMalloc(sizeof(struct ChppAppHeader));
633     if (notification == NULL) {
634       CHPP_LOG_OOM();
635     } else {
636       notificationLen = sizeof(struct ChppAppHeader);
637     }
638   }
639 
640   if (notification != NULL) {
641     notification->header.handle = gGnssServiceContext.service.handle;
642     notification->header.type = CHPP_MESSAGE_TYPE_SERVICE_NOTIFICATION;
643     notification->header.transaction =
644         gGnssServiceContext.controlMeasurementSession.transaction;
645     notification->header.error =
646         (notificationLen > sizeof(struct ChppAppHeader))
647             ? CHPP_APP_ERROR_NONE
648             : CHPP_APP_ERROR_CONVERSION_FAILED;
649     notification->header.command = CHPP_GNSS_MEASUREMENT_RESULT_NOTIFICATION;
650 
651     chppEnqueueTxDatagramOrFail(
652         gGnssServiceContext.service.appContext->transportContext, notification,
653         notificationLen);
654   }
655 
656   gGnssServiceContext.api->releaseMeasurementDataEvent(event);
657 }
658 
659 /************************************************
660  *  Public Functions
661  ***********************************************/
662 
chppRegisterGnssService(struct ChppAppState * appContext)663 void chppRegisterGnssService(struct ChppAppState *appContext) {
664   gGnssServiceContext.api = chrePalGnssGetApi(CHPP_PAL_GNSS_API_VERSION);
665 
666   if (gGnssServiceContext.api == NULL) {
667     CHPP_DEBUG_ASSERT_LOG(false,
668                           "GNSS PAL API incompatible. Cannot register service");
669 
670   } else {
671     chppRegisterService(appContext, (void *)&gGnssServiceContext,
672                         &gGnssServiceContext.service, NULL /*outReqState*/,
673                         &kGnssServiceConfig);
674     CHPP_DEBUG_ASSERT(gGnssServiceContext.service.handle);
675   }
676 }
677 
chppDeregisterGnssService(struct ChppAppState * appContext)678 void chppDeregisterGnssService(struct ChppAppState *appContext) {
679   // TODO
680 
681   UNUSED_VAR(appContext);
682 }
683