1 /* Copyright (c) 2017 The Linux Foundation. All rights reserved.
2  *
3  * Redistribution and use in source and binary forms, with or without
4  * modification, are permitted provided that the following conditions are
5  * met:
6  *     * Redistributions of source code must retain the above copyright
7  *       notice, this list of conditions and the following disclaimer.
8  *     * Redistributions in binary form must reproduce the above
9  *       copyright notice, this list of conditions and the following
10  *       disclaimer in the documentation and/or other materials provided
11  *       with the distribution.
12  *     * Neither the name of The Linux Foundation nor the names of its
13  *       contributors may be used to endorse or promote products derived
14  *       from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #define LOG_NDDEBUG 0
30 #define LOG_TAG "LocSvc_APIClientBase"
31 
32 #include <log_util.h>
33 #include <loc_cfg.h>
34 #include "LocationAPIClientBase.h"
35 
36 #define FLP_CONF_FILE "/vendor/etc/flp.conf"
37 #define GEOFENCE_SESSION_ID -1
38 
LocationAPIClientBase()39 LocationAPIClientBase::LocationAPIClientBase() :
40     mTrackingCallback(nullptr),
41     mBatchingCallback(nullptr),
42     mGeofenceBreachCallback(nullptr),
43     mLocationAPI(nullptr),
44     mLocationControlAPI(nullptr),
45     mBatchSize(-1),
46     mEnabled(false),
47     mTracking(false)
48 {
49 
50     // use recursive mutex, in case callback come from the same thread
51     pthread_mutexattr_t attr;
52     pthread_mutexattr_init(&attr);
53     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
54     pthread_mutex_init(&mMutex, &attr);
55 
56     for (int i = 0; i < REQUEST_MAX; i++) {
57         mRequestQueues[i] = nullptr;
58     }
59 
60     memset(&mConfig, 0, sizeof(GnssConfig));
61 }
62 
locAPISetCallbacks(LocationCallbacks & locationCallbacks)63 void LocationAPIClientBase::locAPISetCallbacks(LocationCallbacks& locationCallbacks)
64 {
65     pthread_mutex_lock(&mMutex);
66 
67     if (locationCallbacks.geofenceBreachCb != nullptr) {
68         mGeofenceBreachCallback = locationCallbacks.geofenceBreachCb;
69         locationCallbacks.geofenceBreachCb =
70             [this](GeofenceBreachNotification geofenceBreachNotification) {
71                 beforeGeofenceBreachCb(geofenceBreachNotification);
72             };
73     }
74 
75     locationCallbacks.capabilitiesCb =
76         [this](LocationCapabilitiesMask capabilitiesMask) {
77             onCapabilitiesCb(capabilitiesMask);
78         };
79     locationCallbacks.responseCb = [this](LocationError error, uint32_t id) {
80         onResponseCb(error, id);
81     };
82     locationCallbacks.collectiveResponseCb =
83         [this](size_t count, LocationError* errors, uint32_t* ids) {
84             onCollectiveResponseCb(count, errors, ids);
85         };
86 
87     if (mLocationAPI == nullptr ) {
88         mLocationAPI = LocationAPI::createInstance(locationCallbacks);
89     } else {
90         mLocationAPI->updateCallbacks(locationCallbacks);
91     }
92 
93     if (mLocationControlAPI == nullptr) {
94         LocationControlCallbacks locationControlCallbacks;
95         locationControlCallbacks.size = sizeof(LocationControlCallbacks);
96 
97         locationControlCallbacks.responseCb =
98             [this](LocationError error, uint32_t id) {
99                 onCtrlResponseCb(error, id);
100             };
101         locationControlCallbacks.collectiveResponseCb =
102             [this](size_t count, LocationError* errors, uint32_t* ids) {
103                 onCtrlCollectiveResponseCb(count, errors, ids);
104             };
105 
106         mLocationControlAPI = LocationControlAPI::createInstance(locationControlCallbacks);
107     }
108 
109     pthread_mutex_unlock(&mMutex);
110 }
111 
~LocationAPIClientBase()112 LocationAPIClientBase::~LocationAPIClientBase()
113 {
114     pthread_mutex_lock(&mMutex);
115 
116     if (mLocationAPI) {
117         mLocationAPI->destroy();
118         mLocationAPI = nullptr;
119     }
120     if (mLocationControlAPI) {
121         mLocationControlAPI->destroy();
122         mLocationControlAPI = nullptr;
123     }
124 
125     for (int i = 0; i < REQUEST_MAX; i++) {
126         if (mRequestQueues[i]) {
127             delete mRequestQueues[i];
128             mRequestQueues[i] = nullptr;
129         }
130     }
131     pthread_mutex_unlock(&mMutex);
132 
133     pthread_mutex_destroy(&mMutex);
134 }
135 
locAPIStartTracking(LocationOptions & options)136 uint32_t LocationAPIClientBase::locAPIStartTracking(LocationOptions& options)
137 {
138     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
139     pthread_mutex_lock(&mMutex);
140     if (mLocationAPI) {
141         if (mTracking) {
142             LOC_LOGW("%s:%d] Existing tracking session present", __FUNCTION__, __LINE__);
143         } else {
144             RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
145             if (requests) {
146                 delete requests;
147                 mRequestQueues[REQUEST_TRACKING] = nullptr;
148             }
149             uint32_t session = mLocationAPI->startTracking(options);
150             LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
151             // onResponseCb might be called from other thread immediately after
152             // startTracking returns, so we are not going to unlock mutex
153             // until StartTrackingRequest is pushed into mRequestQueues[REQUEST_TRACKING]
154             requests = new RequestQueue(session);
155             requests->push(new StartTrackingRequest(*this));
156             mRequestQueues[REQUEST_TRACKING] = requests;
157             mTracking = true;
158         }
159         retVal = LOCATION_ERROR_SUCCESS;
160     }
161     pthread_mutex_unlock(&mMutex);
162 
163     return retVal;
164 }
165 
locAPIStopTracking()166 void LocationAPIClientBase::locAPIStopTracking()
167 {
168     pthread_mutex_lock(&mMutex);
169     if (mLocationAPI) {
170         uint32_t session = 0;
171         RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
172         if (requests) {
173             session = requests->getSession();
174             if (session > 0) {
175                 requests->push(new StopTrackingRequest(*this));
176                 mLocationAPI->stopTracking(session);
177                 mTracking = false;
178             }
179         }
180     }
181     pthread_mutex_unlock(&mMutex);
182 }
183 
locAPIUpdateTrackingOptions(LocationOptions & options)184 void LocationAPIClientBase::locAPIUpdateTrackingOptions(LocationOptions& options)
185 {
186     pthread_mutex_lock(&mMutex);
187     if (mLocationAPI) {
188         uint32_t session = 0;
189         RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
190         if (requests) {
191             session = requests->getSession();
192             if (session > 0) {
193                 requests->push(new UpdateTrackingOptionsRequest(*this));
194                 mLocationAPI->updateTrackingOptions(session, options);
195             }
196         }
197     }
198     pthread_mutex_unlock(&mMutex);
199 }
200 
locAPIGetBatchSize()201 int32_t LocationAPIClientBase::locAPIGetBatchSize()
202 {
203     if (mBatchSize == -1) {
204         const loc_param_s_type flp_conf_param_table[] =
205         {
206             {"BATCH_SIZE", &mBatchSize, nullptr, 'n'},
207         };
208         UTIL_READ_CONF(FLP_CONF_FILE, flp_conf_param_table);
209         if (mBatchSize < 0) {
210             // set mBatchSize to 0 if we got an illegal value from config file
211             mBatchSize = 0;
212         }
213     }
214     return mBatchSize;
215 }
216 
217 
locAPIStartSession(uint32_t id,uint32_t sessionMode,LocationOptions & options)218 uint32_t LocationAPIClientBase::locAPIStartSession(uint32_t id, uint32_t sessionMode,
219         LocationOptions& options)
220 {
221     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
222     pthread_mutex_lock(&mMutex);
223     if (mLocationAPI) {
224 
225         if (mSessionMap.find(id) != mSessionMap.end()) {
226             LOC_LOGE("%s:%d] session %d has already started.", __FUNCTION__, __LINE__, id);
227             retVal = LOCATION_ERROR_ALREADY_STARTED;
228         } else {
229             uint32_t trackingSession = 0;
230             uint32_t batchingSession = 0;
231 
232             if (sessionMode == SESSION_MODE_ON_FIX) {
233                 RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
234                 if (requests) {
235                     delete requests;
236                     mRequestQueues[REQUEST_TRACKING] = nullptr;
237                 }
238                 trackingSession = mLocationAPI->startTracking(options);
239                 LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, trackingSession);
240                 requests = new RequestQueue(trackingSession);
241                 requests->push(new StartTrackingRequest(*this));
242                 mRequestQueues[REQUEST_TRACKING] = requests;
243             } else if (sessionMode == SESSION_MODE_ON_FULL) {
244                 RequestQueue* requests = mRequestQueues[REQUEST_BATCHING];
245                 if (requests) {
246                     delete requests;
247                     mRequestQueues[REQUEST_BATCHING] = nullptr;
248                 }
249                 batchingSession = mLocationAPI->startBatching(options);
250                 LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, batchingSession);
251                 requests = new RequestQueue(batchingSession);
252                 requests->push(new StartBatchingRequest(*this));
253                 mRequestQueues[REQUEST_BATCHING] = requests;
254             }
255 
256             SessionEntity entity;
257             entity.id = id;
258             entity.trackingSession = trackingSession;
259             entity.batchingSession = batchingSession;
260             entity.sessionMode = sessionMode;
261             mSessionMap[id] = entity;
262 
263             retVal = LOCATION_ERROR_SUCCESS;
264         }
265 
266     }
267     pthread_mutex_unlock(&mMutex);
268 
269     return retVal;
270 }
271 
locAPIStopSession(uint32_t id)272 uint32_t LocationAPIClientBase::locAPIStopSession(uint32_t id)
273 {
274     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
275     pthread_mutex_lock(&mMutex);
276     if (mLocationAPI) {
277 
278         if (mSessionMap.find(id) != mSessionMap.end()) {
279             SessionEntity entity = mSessionMap[id];
280 
281             uint32_t trackingSession = entity.trackingSession;
282             uint32_t batchingSession = entity.batchingSession;
283             uint32_t sMode = entity.sessionMode;
284 
285             mSessionMap.erase(id);
286 
287             if (sMode == SESSION_MODE_ON_FIX) {
288                 RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
289                 if (requests) {
290                     requests->push(new StopTrackingRequest(*this));
291                     mLocationAPI->stopTracking(trackingSession);
292                 }
293             } else if (sMode == SESSION_MODE_ON_FULL) {
294                 RequestQueue* requests = mRequestQueues[REQUEST_BATCHING];
295                 if (requests) {
296                     requests->push(new StopBatchingRequest(*this));
297                     mLocationAPI->stopBatching(batchingSession);
298                 }
299             }
300 
301             retVal = LOCATION_ERROR_SUCCESS;
302         } else {
303             retVal = LOCATION_ERROR_ID_UNKNOWN;
304             LOC_LOGE("%s:%d] session %d is not exist.", __FUNCTION__, __LINE__, id);
305         }
306 
307     }
308     pthread_mutex_unlock(&mMutex);
309     return retVal;
310 }
311 
locAPIUpdateSessionOptions(uint32_t id,uint32_t sessionMode,LocationOptions & options)312 uint32_t LocationAPIClientBase::locAPIUpdateSessionOptions(uint32_t id, uint32_t sessionMode,
313         LocationOptions& options)
314 {
315     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
316     pthread_mutex_lock(&mMutex);
317     if (mLocationAPI) {
318 
319         if (mSessionMap.find(id) != mSessionMap.end()) {
320             SessionEntity& entity = mSessionMap[id];
321 
322             uint32_t trackingSession = entity.trackingSession;
323             uint32_t batchingSession = entity.batchingSession;
324             uint32_t sMode = entity.sessionMode;
325 
326             if (sessionMode == SESSION_MODE_ON_FIX) {
327                 if (sMode == SESSION_MODE_ON_FIX) {
328                     RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
329                     if (requests) {
330                         requests->push(new UpdateTrackingOptionsRequest(*this));
331                         mLocationAPI->updateTrackingOptions(trackingSession, options);
332                     }
333                 } else if (sMode == SESSION_MODE_ON_FULL) {
334                     // stop batching
335                     {
336                         RequestQueue* requests = mRequestQueues[REQUEST_BATCHING];
337                         if (requests) {
338                             requests->push(new StopBatchingRequest(*this));
339                             mLocationAPI->stopBatching(batchingSession);
340                             batchingSession = 0;
341                         }
342                     }
343                     // start tracking
344                     {
345                         RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
346                         if (requests) {
347                             delete requests;
348                             mRequestQueues[REQUEST_TRACKING] = nullptr;
349                         }
350                         trackingSession = mLocationAPI->startTracking(options);
351                         LOC_LOGI("%s:%d] start new session: %d",
352                                 __FUNCTION__, __LINE__, trackingSession);
353                         requests = new RequestQueue(trackingSession);
354                         requests->push(new StartTrackingRequest(*this));
355                         mRequestQueues[REQUEST_TRACKING] = requests;
356                     }
357                 }
358             } else if (sessionMode == SESSION_MODE_ON_FULL) {
359                 if (sMode == SESSION_MODE_ON_FIX) {
360                     // stop tracking
361                     {
362                         RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
363                         if (requests) {
364                             requests->push(new StopTrackingRequest(*this));
365                             mLocationAPI->stopTracking(trackingSession);
366                             trackingSession = 0;
367                         }
368                     }
369                     // start batching
370                     {
371                         RequestQueue* requests = mRequestQueues[REQUEST_BATCHING];
372                         if (requests) {
373                             delete requests;
374                             mRequestQueues[REQUEST_BATCHING] = nullptr;
375                         }
376                         batchingSession = mLocationAPI->startBatching(options);
377                         LOC_LOGI("%s:%d] start new session: %d",
378                                 __FUNCTION__, __LINE__, batchingSession);
379                         requests = new RequestQueue(batchingSession);
380                         requests->push(new StartBatchingRequest(*this));
381                         mRequestQueues[REQUEST_BATCHING] = requests;
382                     }
383                 } else if (sMode == SESSION_MODE_ON_FULL) {
384                     RequestQueue* requests = mRequestQueues[REQUEST_BATCHING];
385                     requests = mRequestQueues[REQUEST_BATCHING];
386                     if (requests) {
387                         requests->push(new UpdateBatchingOptionsRequest(*this));
388                         mLocationAPI->updateBatchingOptions(batchingSession, options);
389                     }
390                 }
391             }
392 
393             entity.trackingSession = trackingSession;
394             entity.batchingSession = batchingSession;
395             entity.sessionMode = sessionMode;
396 
397             retVal = LOCATION_ERROR_SUCCESS;
398         } else {
399             retVal = LOCATION_ERROR_ID_UNKNOWN;
400             LOC_LOGE("%s:%d] session %d is not exist.", __FUNCTION__, __LINE__, id);
401         }
402 
403     }
404     pthread_mutex_unlock(&mMutex);
405     return retVal;
406 }
407 
locAPIGetBatchedLocations(size_t count)408 void LocationAPIClientBase::locAPIGetBatchedLocations(size_t count)
409 {
410     pthread_mutex_lock(&mMutex);
411     if (mLocationAPI) {
412         uint32_t session = 0;
413         RequestQueue* requests = mRequestQueues[REQUEST_BATCHING];
414         if (requests) {
415             session = requests->getSession();
416             if (session > 0) {
417                 requests->push(new GetBatchedLocationsRequest(*this));
418                 mLocationAPI->getBatchedLocations(session, count);
419             }
420         }
421     }
422     pthread_mutex_unlock(&mMutex);
423 }
424 
locAPIAddGeofences(size_t count,uint32_t * ids,GeofenceOption * options,GeofenceInfo * data)425 uint32_t LocationAPIClientBase::locAPIAddGeofences(
426         size_t count, uint32_t* ids, GeofenceOption* options, GeofenceInfo* data)
427 {
428     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
429     pthread_mutex_lock(&mMutex);
430     if (mLocationAPI) {
431         RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE];
432         if (!requests) {
433             // Create a new RequestQueue for Geofenceing if we've not had one.
434             // The RequestQueue will be released when LocationAPIClientBase is released.
435             requests = new RequestQueue(GEOFENCE_SESSION_ID);
436             mRequestQueues[REQUEST_GEOFENCE] = requests;
437         }
438         uint32_t* sessions = mLocationAPI->addGeofences(count, options, data);
439         if (sessions) {
440             LOC_LOGI("%s:%d] start new sessions: %p", __FUNCTION__, __LINE__, sessions);
441             requests->push(new AddGeofencesRequest(*this));
442 
443             for (size_t i = 0; i < count; i++) {
444                 mGeofenceBiDict.set(ids[i], sessions[i], options[i].breachTypeMask);
445             }
446             retVal = LOCATION_ERROR_SUCCESS;
447         }
448     }
449     pthread_mutex_unlock(&mMutex);
450 
451     return retVal;
452 }
453 
locAPIRemoveGeofences(size_t count,uint32_t * ids)454 void LocationAPIClientBase::locAPIRemoveGeofences(size_t count, uint32_t* ids)
455 {
456     pthread_mutex_lock(&mMutex);
457     if (mLocationAPI) {
458         uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
459 
460         RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE];
461         if (requests) {
462             size_t j = 0;
463             for (size_t i = 0; i < count; i++) {
464                 sessions[j] = mGeofenceBiDict.getSession(ids[i]);
465                 if (sessions[j] > 0) {
466                     j++;
467                 }
468             }
469             if (j > 0) {
470                 requests->push(new RemoveGeofencesRequest(*this));
471                 mLocationAPI->removeGeofences(j, sessions);
472             }
473         }
474 
475         free(sessions);
476     }
477     pthread_mutex_unlock(&mMutex);
478 }
479 
locAPIModifyGeofences(size_t count,uint32_t * ids,GeofenceOption * options)480 void LocationAPIClientBase::locAPIModifyGeofences(
481         size_t count, uint32_t* ids, GeofenceOption* options)
482 {
483     pthread_mutex_lock(&mMutex);
484     if (mLocationAPI) {
485         uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
486 
487         RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE];
488         if (requests) {
489             size_t j = 0;
490             for (size_t i = 0; i < count; i++) {
491                 sessions[j] = mGeofenceBiDict.getSession(ids[i]);
492                 if (sessions[j] > 0) {
493                     mGeofenceBiDict.set(ids[i], sessions[j], options[i].breachTypeMask);
494                     j++;
495                 }
496             }
497             if (j > 0) {
498                 requests->push(new ModifyGeofencesRequest(*this));
499                 mLocationAPI->modifyGeofences(j, sessions, options);
500             }
501         }
502 
503         free(sessions);
504     }
505     pthread_mutex_unlock(&mMutex);
506 }
507 
locAPIPauseGeofences(size_t count,uint32_t * ids)508 void LocationAPIClientBase::locAPIPauseGeofences(size_t count, uint32_t* ids)
509 {
510     pthread_mutex_lock(&mMutex);
511     if (mLocationAPI) {
512         uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
513 
514         RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE];
515         if (requests) {
516             size_t j = 0;
517             for (size_t i = 0; i < count; i++) {
518                 sessions[j] = mGeofenceBiDict.getSession(ids[i]);
519                 if (sessions[j] > 0) {
520                     j++;
521                 }
522             }
523             if (j > 0) {
524                 requests->push(new PauseGeofencesRequest(*this));
525                 mLocationAPI->pauseGeofences(j, sessions);
526             }
527         }
528 
529         free(sessions);
530     }
531     pthread_mutex_unlock(&mMutex);
532 }
533 
locAPIResumeGeofences(size_t count,uint32_t * ids,GeofenceBreachTypeMask * mask)534 void LocationAPIClientBase::locAPIResumeGeofences(
535         size_t count, uint32_t* ids, GeofenceBreachTypeMask* mask)
536 {
537     pthread_mutex_lock(&mMutex);
538     if (mLocationAPI) {
539         uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
540 
541         RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE];
542         if (requests) {
543             size_t j = 0;
544             for (size_t i = 0; i < count; i++) {
545                 sessions[j] = mGeofenceBiDict.getSession(ids[i]);
546                 if (sessions[j] > 0) {
547                     if (mask) {
548                         mGeofenceBiDict.set(ids[i], sessions[j], mask[i]);
549                     }
550                     j++;
551                 }
552             }
553             if (j > 0) {
554                 requests->push(new ResumeGeofencesRequest(*this));
555                 mLocationAPI->resumeGeofences(j, sessions);
556             }
557         }
558 
559         free(sessions);
560     }
561     pthread_mutex_unlock(&mMutex);
562 }
563 
locAPIRemoveAllGeofences()564 void LocationAPIClientBase::locAPIRemoveAllGeofences()
565 {
566     pthread_mutex_lock(&mMutex);
567     if (mLocationAPI) {
568         std::vector<uint32_t> sessionsVec = mGeofenceBiDict.getAllSessions();
569         size_t count = sessionsVec.size();
570         uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
571 
572         RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE];
573         if (requests) {
574             size_t j = 0;
575             for (size_t i = 0; i < count; i++) {
576                 sessions[j] = sessionsVec[i];
577                 if (sessions[j] > 0) {
578                     j++;
579                 }
580             }
581             if (j > 0) {
582                 requests->push(new RemoveGeofencesRequest(*this));
583                 mLocationAPI->removeGeofences(j, sessions);
584             }
585         }
586 
587         free(sessions);
588     }
589     pthread_mutex_unlock(&mMutex);
590 }
591 
locAPIGnssNiResponse(uint32_t id,GnssNiResponse response)592 void LocationAPIClientBase::locAPIGnssNiResponse(uint32_t id, GnssNiResponse response)
593 {
594     pthread_mutex_lock(&mMutex);
595     if (mLocationAPI) {
596         RequestQueue* requests = mRequestQueues[REQUEST_NIRESPONSE];
597         if (requests) {
598             delete requests;
599             mRequestQueues[REQUEST_NIRESPONSE] = nullptr;
600         }
601         uint32_t session = id;
602         mLocationAPI->gnssNiResponse(id, response);
603         LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
604         requests = new RequestQueue(session);
605         requests->push(new GnssNiResponseRequest(*this));
606         mRequestQueues[REQUEST_NIRESPONSE] = requests;
607     }
608     pthread_mutex_unlock(&mMutex);
609 }
610 
locAPIGnssDeleteAidingData(GnssAidingData & data)611 uint32_t LocationAPIClientBase::locAPIGnssDeleteAidingData(GnssAidingData& data)
612 {
613     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
614     pthread_mutex_lock(&mMutex);
615     if (mLocationControlAPI) {
616         RequestQueue* requests = mRequestQueues[REQUEST_DELETEAIDINGDATA];
617         if (requests) {
618             delete requests;
619             mRequestQueues[REQUEST_DELETEAIDINGDATA] = nullptr;
620         }
621         uint32_t session = mLocationControlAPI->gnssDeleteAidingData(data);
622         LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
623         requests = new RequestQueue(session);
624         requests->push(new GnssDeleteAidingDataRequest(*this));
625         mRequestQueues[REQUEST_DELETEAIDINGDATA] = requests;
626 
627         retVal = LOCATION_ERROR_SUCCESS;
628     }
629     pthread_mutex_unlock(&mMutex);
630 
631     return retVal;
632 }
633 
locAPIEnable(LocationTechnologyType techType)634 uint32_t LocationAPIClientBase::locAPIEnable(LocationTechnologyType techType)
635 {
636     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
637     pthread_mutex_lock(&mMutex);
638     if (mEnabled) {
639         // just return success if already enabled
640         retVal = LOCATION_ERROR_SUCCESS;
641     } else if (mLocationControlAPI) {
642         RequestQueue* requests = mRequestQueues[REQUEST_CONTROL];
643         if (requests) {
644             delete requests;
645             mRequestQueues[REQUEST_CONTROL] = nullptr;
646         }
647         uint32_t session = mLocationControlAPI->enable(techType);
648         LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
649         requests = new RequestQueue(session);
650         mRequestQueues[REQUEST_CONTROL] = requests;
651         if (requests) {
652             requests->push(new EnableRequest(*this));
653             retVal = LOCATION_ERROR_SUCCESS;
654             mEnabled = true;
655         }
656     }
657     pthread_mutex_unlock(&mMutex);
658 
659     return retVal;
660 }
661 
locAPIDisable()662 void LocationAPIClientBase::locAPIDisable()
663 {
664     pthread_mutex_lock(&mMutex);
665     if (mEnabled && mLocationControlAPI) {
666         uint32_t session = 0;
667         RequestQueue* requests = mRequestQueues[REQUEST_CONTROL];
668         if (requests) {
669             session = requests->getSession();
670             if (session > 0) {
671                 requests->push(new DisableRequest(*this));
672                 mLocationControlAPI->disable(session);
673                 mEnabled = false;
674             }
675         }
676     }
677     pthread_mutex_unlock(&mMutex);
678 }
679 
locAPIGnssUpdateConfig(GnssConfig config)680 uint32_t LocationAPIClientBase::locAPIGnssUpdateConfig(GnssConfig config)
681 {
682     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
683     if (memcmp(&mConfig, &config, sizeof(GnssConfig)) == 0) {
684         LOC_LOGV("%s:%d] GnssConfig is identical to previous call", __FUNCTION__, __LINE__);
685         retVal = LOCATION_ERROR_SUCCESS;
686         return retVal;
687     }
688 
689     pthread_mutex_lock(&mMutex);
690     if (mLocationControlAPI) {
691 
692         memcpy(&mConfig, &config, sizeof(GnssConfig));
693 
694         uint32_t session = 0;
695         RequestQueue* requests = mRequestQueues[REQUEST_CONFIG];
696         uint32_t* idArray = mLocationControlAPI->gnssUpdateConfig(config);
697         LOC_LOGV("%s:%d] gnssUpdateConfig return array: %p", __FUNCTION__, __LINE__, idArray);
698         if (!requests && idArray != nullptr) {
699             requests = new RequestQueue(idArray[0]);
700             mRequestQueues[REQUEST_CONFIG] = requests;
701         }
702         if (requests) {
703             requests->push(new GnssUpdateConfigRequest(*this));
704             retVal = LOCATION_ERROR_SUCCESS;
705         }
706     }
707     pthread_mutex_unlock(&mMutex);
708     return retVal;
709 }
710 
beforeGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification)711 void LocationAPIClientBase::beforeGeofenceBreachCb(
712         GeofenceBreachNotification geofenceBreachNotification)
713 {
714     if (mGeofenceBreachCallback == nullptr)
715         return;
716     uint32_t* ids = (uint32_t*)malloc(sizeof(uint32_t) * geofenceBreachNotification.count);
717     uint32_t* backup = geofenceBreachNotification.ids;
718     size_t n = geofenceBreachNotification.count;
719 
720     size_t count = 0;
721     for (size_t i = 0; i < n; i++) {
722         uint32_t id = mGeofenceBiDict.getId(geofenceBreachNotification.ids[i]);
723         GeofenceBreachTypeMask type = mGeofenceBiDict.getType(geofenceBreachNotification.ids[i]);
724         // if type == 0, we will not head into the fllowing block anyway.
725         // so we don't need to check id and type
726         if ((geofenceBreachNotification.type == GEOFENCE_BREACH_ENTER &&
727             (type & GEOFENCE_BREACH_ENTER_BIT)) ||
728             (geofenceBreachNotification.type == GEOFENCE_BREACH_EXIT &&
729             (type & GEOFENCE_BREACH_EXIT_BIT))
730            ) {
731             ids[count] = id;
732             count++;
733         }
734     }
735     geofenceBreachNotification.count = count;
736     geofenceBreachNotification.ids = ids;
737     mGeofenceBreachCallback(geofenceBreachNotification);
738 
739     // restore ids
740     geofenceBreachNotification.ids = backup;
741     geofenceBreachNotification.count = n;
742     free(ids);
743 }
744 
onResponseCb(LocationError error,uint32_t id)745 void LocationAPIClientBase::onResponseCb(LocationError error, uint32_t id)
746 {
747     if (error != LOCATION_ERROR_SUCCESS) {
748         LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, error, id);
749     } else {
750         LOC_LOGV("%s:%d] error: %d id: %d", __FUNCTION__, __LINE__, error, id);
751     }
752     LocationAPIRequest* request = getRequestBySession(id);
753     if (request) {
754         request->onResponse(error);
755         delete request;
756     }
757 }
758 
onCollectiveResponseCb(size_t count,LocationError * errors,uint32_t * ids)759 void LocationAPIClientBase::onCollectiveResponseCb(
760         size_t count, LocationError* errors, uint32_t* ids)
761 {
762     for (size_t i = 0; i < count; i++) {
763         if (errors[i] != LOCATION_ERROR_SUCCESS) {
764             LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
765         } else {
766             LOC_LOGV("%s:%d] error: %d id: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
767         }
768     }
769     LocationAPIRequest* request = nullptr;
770     pthread_mutex_lock(&mMutex);
771     if (mRequestQueues[REQUEST_GEOFENCE] != nullptr) {
772         request = mRequestQueues[REQUEST_GEOFENCE]->pop();
773     }
774     pthread_mutex_unlock(&mMutex);
775     if (request) {
776         request->onCollectiveResponse(count, errors, ids);
777         delete request;
778     }
779 }
780 
onCtrlResponseCb(LocationError error,uint32_t id)781 void LocationAPIClientBase::onCtrlResponseCb(LocationError error, uint32_t id)
782 {
783     if (error != LOCATION_ERROR_SUCCESS) {
784         LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, error, id);
785     } else {
786         LOC_LOGV("%s:%d] error: %d id: %d", __FUNCTION__, __LINE__, error, id);
787     }
788     LocationAPIRequest* request = getRequestBySession(id);
789     if (request) {
790         request->onResponse(error);
791         delete request;
792     }
793 }
794 
onCtrlCollectiveResponseCb(size_t count,LocationError * errors,uint32_t * ids)795 void LocationAPIClientBase::onCtrlCollectiveResponseCb(
796         size_t count, LocationError* errors, uint32_t* ids)
797 {
798     for (size_t i = 0; i < count; i++) {
799         if (errors[i] != LOCATION_ERROR_SUCCESS) {
800             LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
801         } else {
802             LOC_LOGV("%s:%d] error: %d id: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
803         }
804     }
805     LocationAPIRequest* request = nullptr;
806     pthread_mutex_lock(&mMutex);
807     if (mRequestQueues[REQUEST_CONFIG] != nullptr) {
808         request = mRequestQueues[REQUEST_CONFIG]->pop();
809     }
810     pthread_mutex_unlock(&mMutex);
811     if (request) {
812         request->onCollectiveResponse(count, errors, ids);
813         delete request;
814     }
815 }
816 
817 LocationAPIClientBase::LocationAPIRequest*
getRequestBySession(uint32_t session)818 LocationAPIClientBase::getRequestBySession(uint32_t session)
819 {
820     pthread_mutex_lock(&mMutex);
821     LocationAPIRequest* request = nullptr;
822     for (int i = 0; i < REQUEST_MAX; i++) {
823         if (i != REQUEST_GEOFENCE &&
824                 i != REQUEST_CONFIG &&
825                 mRequestQueues[i] &&
826                 mRequestQueues[i]->getSession() == session) {
827             request = mRequestQueues[i]->pop();
828             break;
829         }
830     }
831     pthread_mutex_unlock(&mMutex);
832     return request;
833 }
834