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 
LocationAPIClientBase()38 LocationAPIClientBase::LocationAPIClientBase() :
39     mTrackingCallback(nullptr),
40     mBatchingCallback(nullptr),
41     mGeofenceBreachCallback(nullptr),
42     mLocationAPI(nullptr),
43     mLocationControlAPI(nullptr),
44     mBatchSize(-1)
45 {
46 
47     // use recursive mutex, in case callback come from the same thread
48     pthread_mutexattr_t attr;
49     pthread_mutexattr_init(&attr);
50     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
51     pthread_mutex_init(&mMutex, &attr);
52 
53     for (int i = 0; i < REQUEST_MAX; i++) {
54         mRequestQueues[i] = nullptr;
55     }
56 
57     memset(&mConfig, 0, sizeof(GnssConfig));
58 }
59 
locAPISetCallbacks(LocationCallbacks & locationCallbacks)60 void LocationAPIClientBase::locAPISetCallbacks(LocationCallbacks& locationCallbacks)
61 {
62     if (locationCallbacks.geofenceBreachCb != nullptr) {
63         mGeofenceBreachCallback = locationCallbacks.geofenceBreachCb;
64         locationCallbacks.geofenceBreachCb =
65             [this](GeofenceBreachNotification geofenceBreachNotification) {
66                 beforeGeofenceBreachCb(geofenceBreachNotification);
67             };
68     }
69 
70     locationCallbacks.capabilitiesCb =
71         [this](LocationCapabilitiesMask capabilitiesMask) {
72             onCapabilitiesCb(capabilitiesMask);
73         };
74     locationCallbacks.responseCb = [this](LocationError error, uint32_t id) {
75         onResponseCb(error, id);
76     };
77     locationCallbacks.collectiveResponseCb =
78         [this](size_t count, LocationError* errors, uint32_t* ids) {
79             onCollectiveResponseCb(count, errors, ids);
80         };
81 
82     if (mLocationAPI == nullptr ) {
83         mLocationAPI = LocationAPI::createInstance(locationCallbacks);
84     } else {
85         mLocationAPI->updateCallbacks(locationCallbacks);
86     }
87 
88     if (mLocationControlAPI == nullptr) {
89         LocationControlCallbacks locationControlCallbacks;
90         locationControlCallbacks.size = sizeof(LocationControlCallbacks);
91 
92         locationControlCallbacks.responseCb =
93             [this](LocationError error, uint32_t id) {
94                 onCtrlResponseCb(error, id);
95             };
96         locationControlCallbacks.collectiveResponseCb =
97             [this](size_t count, LocationError* errors, uint32_t* ids) {
98                 onCtrlCollectiveResponseCb(count, errors, ids);
99             };
100 
101         mLocationControlAPI = LocationControlAPI::createInstance(locationControlCallbacks);
102     }
103 }
104 
~LocationAPIClientBase()105 LocationAPIClientBase::~LocationAPIClientBase()
106 {
107     if (mLocationAPI) {
108         mLocationAPI->destroy();
109         mLocationAPI = nullptr;
110     }
111     if (mLocationControlAPI) {
112         mLocationControlAPI->destroy();
113         mLocationControlAPI = nullptr;
114     }
115 
116     pthread_mutex_lock(&mMutex);
117     for (int i = 0; i < REQUEST_MAX; i++) {
118         if (mRequestQueues[i]) {
119             delete mRequestQueues[i];
120             mRequestQueues[i] = nullptr;
121         }
122     }
123     pthread_mutex_unlock(&mMutex);
124 
125     pthread_mutex_destroy(&mMutex);
126 }
127 
locAPIStartTracking(LocationOptions & options)128 uint32_t LocationAPIClientBase::locAPIStartTracking(LocationOptions& options)
129 {
130     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
131     if (mLocationAPI) {
132         pthread_mutex_lock(&mMutex);
133         RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
134         if (requests) {
135             delete requests;
136         }
137         uint32_t session = mLocationAPI->startTracking(options);
138         LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
139         // onResponseCb might be called from other thread immediately after
140         // startTracking returns, so we are not going to unlock mutex
141         // until StartTrackingRequest is pushed into mRequestQueues[REQUEST_TRACKING]
142         requests = new RequestQueue(session);
143         requests->push(new StartTrackingRequest(*this));
144         mRequestQueues[REQUEST_TRACKING] = requests;
145         pthread_mutex_unlock(&mMutex);
146 
147         retVal = LOCATION_ERROR_SUCCESS;
148     }
149 
150     return retVal;
151 }
152 
locAPIStopTracking()153 void LocationAPIClientBase::locAPIStopTracking()
154 {
155     if (mLocationAPI) {
156         pthread_mutex_lock(&mMutex);
157         uint32_t session = -1;
158         RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
159         if (requests) {
160             session = requests->getSession();
161             requests->push(new StopTrackingRequest(*this));
162             mLocationAPI->stopTracking(session);
163         }
164         pthread_mutex_unlock(&mMutex);
165     }
166 }
167 
locAPIUpdateTrackingOptions(LocationOptions & options)168 void LocationAPIClientBase::locAPIUpdateTrackingOptions(LocationOptions& options)
169 {
170     if (mLocationAPI) {
171         pthread_mutex_lock(&mMutex);
172         uint32_t session = -1;
173         RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
174         if (requests) {
175             session = requests->getSession();
176             requests->push(new UpdateTrackingOptionsRequest(*this));
177             mLocationAPI->updateTrackingOptions(session, options);
178         }
179         pthread_mutex_unlock(&mMutex);
180     }
181 }
182 
locAPIGetBatchSize()183 int32_t LocationAPIClientBase::locAPIGetBatchSize()
184 {
185     if (mBatchSize == -1) {
186         const loc_param_s_type flp_conf_param_table[] =
187         {
188             {"BATCH_SIZE", &mBatchSize, nullptr, 'n'},
189         };
190         UTIL_READ_CONF(FLP_CONF_FILE, flp_conf_param_table);
191         if (mBatchSize < 0) {
192             // set mBatchSize to 0 if we got an illegal value from config file
193             mBatchSize = 0;
194         }
195     }
196     return mBatchSize;
197 }
198 
199 
locAPIStartSession(uint32_t id,uint32_t sessionMode,LocationOptions & options)200 uint32_t LocationAPIClientBase::locAPIStartSession(uint32_t id, uint32_t sessionMode,
201         LocationOptions& options)
202 {
203     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
204     if (mLocationAPI) {
205         pthread_mutex_lock(&mMutex);
206 
207         if (mSessionMap.find(id) != mSessionMap.end()) {
208             LOC_LOGE("%s:%d] session %d has already started.", __FUNCTION__, __LINE__, id);
209             retVal = LOCATION_ERROR_ALREADY_STARTED;
210         } else {
211             uint32_t trackingSession = 0;
212             uint32_t batchingSession = 0;
213 
214             if (sessionMode == SESSION_MODE_ON_FIX) {
215                 RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
216                 if (requests) {
217                     delete requests;
218                 }
219                 trackingSession = mLocationAPI->startTracking(options);
220                 LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, trackingSession);
221                 requests = new RequestQueue(trackingSession);
222                 requests->push(new StartTrackingRequest(*this));
223                 mRequestQueues[REQUEST_TRACKING] = requests;
224             } else if (sessionMode == SESSION_MODE_ON_FULL) {
225                 RequestQueue* requests = mRequestQueues[REQUEST_BATCHING];
226                 if (requests) {
227                     delete requests;
228                 }
229                 batchingSession = mLocationAPI->startBatching(options);
230                 LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, batchingSession);
231                 requests = new RequestQueue(batchingSession);
232                 requests->push(new StartBatchingRequest(*this));
233                 mRequestQueues[REQUEST_BATCHING] = requests;
234             }
235 
236             SessionEntity entity;
237             entity.id = id;
238             entity.trackingSession = trackingSession;
239             entity.batchingSession = batchingSession;
240             entity.sessionMode = sessionMode;
241             mSessionMap[id] = entity;
242 
243             retVal = LOCATION_ERROR_SUCCESS;
244         }
245 
246         pthread_mutex_unlock(&mMutex);
247     }
248 
249     return retVal;
250 }
251 
locAPIStopSession(uint32_t id)252 uint32_t LocationAPIClientBase::locAPIStopSession(uint32_t id)
253 {
254     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
255     if (mLocationAPI) {
256         pthread_mutex_lock(&mMutex);
257 
258         if (mSessionMap.find(id) != mSessionMap.end()) {
259             SessionEntity entity = mSessionMap[id];
260 
261             uint32_t trackingSession = entity.trackingSession;
262             uint32_t batchingSession = entity.batchingSession;
263             uint32_t sMode = entity.sessionMode;
264 
265             mSessionMap.erase(id);
266 
267             if (sMode == SESSION_MODE_ON_FIX) {
268                 RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
269                 if (requests) {
270                     requests->push(new StopTrackingRequest(*this));
271                     mLocationAPI->stopTracking(trackingSession);
272                 }
273             } else if (sMode == SESSION_MODE_ON_FULL) {
274                 RequestQueue* requests = mRequestQueues[REQUEST_BATCHING];
275                 if (requests) {
276                     requests->push(new StopBatchingRequest(*this));
277                     mLocationAPI->stopBatching(batchingSession);
278                 }
279             }
280 
281             retVal = LOCATION_ERROR_SUCCESS;
282         } else {
283             retVal = LOCATION_ERROR_ID_UNKNOWN;
284             LOC_LOGE("%s:%d] session %d is not exist.", __FUNCTION__, __LINE__, id);
285         }
286 
287         pthread_mutex_unlock(&mMutex);
288     }
289     return retVal;
290 }
291 
locAPIUpdateSessionOptions(uint32_t id,uint32_t sessionMode,LocationOptions & options)292 uint32_t LocationAPIClientBase::locAPIUpdateSessionOptions(uint32_t id, uint32_t sessionMode,
293         LocationOptions& options)
294 {
295     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
296     if (mLocationAPI) {
297         pthread_mutex_lock(&mMutex);
298 
299         if (mSessionMap.find(id) != mSessionMap.end()) {
300             SessionEntity& entity = mSessionMap[id];
301 
302             uint32_t trackingSession = entity.trackingSession;
303             uint32_t batchingSession = entity.batchingSession;
304             uint32_t sMode = entity.sessionMode;
305 
306             if (sessionMode == SESSION_MODE_ON_FIX) {
307                 if (sMode == SESSION_MODE_ON_FIX) {
308                     RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
309                     if (requests) {
310                         requests->push(new UpdateTrackingOptionsRequest(*this));
311                         mLocationAPI->updateTrackingOptions(trackingSession, options);
312                     }
313                 } else if (sMode == SESSION_MODE_ON_FULL) {
314                     // stop batching
315                     {
316                         RequestQueue* requests = mRequestQueues[REQUEST_BATCHING];
317                         if (requests) {
318                             requests->push(new StopBatchingRequest(*this));
319                             mLocationAPI->stopBatching(batchingSession);
320                             batchingSession = 0;
321                         }
322                     }
323                     // start tracking
324                     {
325                         RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
326                         if (requests) {
327                             delete requests;
328                         }
329                         trackingSession = mLocationAPI->startTracking(options);
330                         LOC_LOGI("%s:%d] start new session: %d",
331                                 __FUNCTION__, __LINE__, trackingSession);
332                         requests = new RequestQueue(trackingSession);
333                         requests->push(new StartTrackingRequest(*this));
334                         mRequestQueues[REQUEST_TRACKING] = requests;
335                     }
336                 }
337             } else if (sessionMode == SESSION_MODE_ON_FULL) {
338                 if (sMode == SESSION_MODE_ON_FIX) {
339                     // stop tracking
340                     {
341                         RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
342                         if (requests) {
343                             requests->push(new StopTrackingRequest(*this));
344                             mLocationAPI->stopTracking(trackingSession);
345                             trackingSession = 0;
346                         }
347                     }
348                     // start batching
349                     {
350                         RequestQueue* requests = mRequestQueues[REQUEST_BATCHING];
351                         if (requests) {
352                             delete requests;
353                         }
354                         batchingSession = mLocationAPI->startBatching(options);
355                         LOC_LOGI("%s:%d] start new session: %d",
356                                 __FUNCTION__, __LINE__, batchingSession);
357                         requests = new RequestQueue(batchingSession);
358                         requests->push(new StartBatchingRequest(*this));
359                         mRequestQueues[REQUEST_BATCHING] = requests;
360                     }
361                 } else if (sMode == SESSION_MODE_ON_FULL) {
362                     RequestQueue* requests = mRequestQueues[REQUEST_BATCHING];
363                     requests = mRequestQueues[REQUEST_BATCHING];
364                     if (requests) {
365                         requests->push(new UpdateBatchingOptionsRequest(*this));
366                         mLocationAPI->updateBatchingOptions(batchingSession, options);
367                     }
368                 }
369             }
370 
371             entity.trackingSession = trackingSession;
372             entity.batchingSession = batchingSession;
373             entity.sessionMode = sessionMode;
374 
375             retVal = LOCATION_ERROR_SUCCESS;
376         } else {
377             retVal = LOCATION_ERROR_ID_UNKNOWN;
378             LOC_LOGE("%s:%d] session %d is not exist.", __FUNCTION__, __LINE__, id);
379         }
380 
381         pthread_mutex_unlock(&mMutex);
382     }
383     return retVal;
384 }
385 
locAPIGetBatchedLocations(size_t count)386 void LocationAPIClientBase::locAPIGetBatchedLocations(size_t count)
387 {
388     if (mLocationAPI) {
389         pthread_mutex_lock(&mMutex);
390         uint32_t session = -1;
391         RequestQueue* requests = mRequestQueues[REQUEST_BATCHING];
392         if (requests) {
393             session = requests->getSession();
394             requests->push(new GetBatchedLocationsRequest(*this));
395             mLocationAPI->getBatchedLocations(session, count);
396         }
397         pthread_mutex_unlock(&mMutex);
398     }
399 }
400 
locAPIAddGeofences(size_t count,uint32_t * ids,GeofenceOption * options,GeofenceInfo * data)401 uint32_t LocationAPIClientBase::locAPIAddGeofences(
402         size_t count, uint32_t* ids, GeofenceOption* options, GeofenceInfo* data)
403 {
404     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
405     if (mLocationAPI) {
406         pthread_mutex_lock(&mMutex);
407         RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE];
408         if (requests) {
409             delete requests;
410         }
411         uint32_t* sessions = mLocationAPI->addGeofences(count, options, data);
412         if (sessions) {
413             LOC_LOGI("%s:%d] start new sessions: %p", __FUNCTION__, __LINE__, sessions);
414             requests = new RequestQueue(-1);
415             requests->push(new AddGeofencesRequest(*this));
416             mRequestQueues[REQUEST_GEOFENCE] = requests;
417 
418             for (size_t i = 0; i < count; i++) {
419                 mGeofenceBiDict.set(ids[i], sessions[i], options[i].breachTypeMask);
420             }
421             retVal = LOCATION_ERROR_SUCCESS;
422         }
423         pthread_mutex_unlock(&mMutex);
424     }
425 
426     return retVal;
427 }
428 
locAPIRemoveGeofences(size_t count,uint32_t * ids)429 void LocationAPIClientBase::locAPIRemoveGeofences(size_t count, uint32_t* ids)
430 {
431     if (mLocationAPI) {
432         uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
433 
434         pthread_mutex_lock(&mMutex);
435         RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE];
436         if (requests) {
437             for (size_t i = 0; i < count; i++) {
438                 sessions[i] = mGeofenceBiDict.getSession(ids[i]);
439             }
440             requests->push(new RemoveGeofencesRequest(*this));
441             mLocationAPI->removeGeofences(count, sessions);
442         }
443         pthread_mutex_unlock(&mMutex);
444 
445         free(sessions);
446     }
447 }
448 
locAPIModifyGeofences(size_t count,uint32_t * ids,GeofenceOption * options)449 void LocationAPIClientBase::locAPIModifyGeofences(
450         size_t count, uint32_t* ids, GeofenceOption* options)
451 {
452     if (mLocationAPI) {
453         uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
454 
455         pthread_mutex_lock(&mMutex);
456         RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE];
457         if (requests) {
458             for (size_t i = 0; i < count; i++) {
459                 sessions[i] = mGeofenceBiDict.getSession(ids[i]);
460                 mGeofenceBiDict.set(ids[i], sessions[i], options[i].breachTypeMask);
461             }
462             requests->push(new ModifyGeofencesRequest(*this));
463             mLocationAPI->modifyGeofences(count, sessions, options);
464         }
465         pthread_mutex_unlock(&mMutex);
466 
467         free(sessions);
468     }
469 }
470 
locAPIPauseGeofences(size_t count,uint32_t * ids)471 void LocationAPIClientBase::locAPIPauseGeofences(size_t count, uint32_t* ids)
472 {
473     if (mLocationAPI) {
474         uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
475 
476         pthread_mutex_lock(&mMutex);
477         RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE];
478         if (requests) {
479             for (size_t i = 0; i < count; i++) {
480                 sessions[i] = mGeofenceBiDict.getSession(ids[i]);
481             }
482             requests->push(new PauseGeofencesRequest(*this));
483             mLocationAPI->pauseGeofences(count, sessions);
484         }
485         pthread_mutex_unlock(&mMutex);
486 
487         free(sessions);
488     }
489 }
490 
locAPIResumeGeofences(size_t count,uint32_t * ids,GeofenceBreachTypeMask * mask)491 void LocationAPIClientBase::locAPIResumeGeofences(
492         size_t count, uint32_t* ids, GeofenceBreachTypeMask* mask)
493 {
494     if (mLocationAPI) {
495         uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
496 
497         pthread_mutex_lock(&mMutex);
498         RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE];
499         if (requests) {
500             for (size_t i = 0; i < count; i++) {
501                 sessions[i] = mGeofenceBiDict.getSession(ids[i]);
502                 if (mask) {
503                     mGeofenceBiDict.set(ids[i], sessions[i], mask[i]);
504                 }
505             }
506             requests->push(new ResumeGeofencesRequest(*this));
507             mLocationAPI->resumeGeofences(count, sessions);
508         }
509         pthread_mutex_unlock(&mMutex);
510 
511         free(sessions);
512     }
513 }
514 
locAPIRemoveAllGeofences()515 void LocationAPIClientBase::locAPIRemoveAllGeofences()
516 {
517     if (mLocationAPI) {
518         std::vector<uint32_t> sessionsVec = mGeofenceBiDict.getAllSessions();
519         size_t count = sessionsVec.size();
520         uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
521 
522         pthread_mutex_lock(&mMutex);
523         RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE];
524         if (requests) {
525             for (size_t i = 0; i < count; i++) {
526                 sessions[i] = sessionsVec[i];
527             }
528             requests->push(new RemoveGeofencesRequest(*this));
529             mLocationAPI->removeGeofences(count, sessions);
530         }
531         pthread_mutex_unlock(&mMutex);
532 
533         free(sessions);
534     }
535 }
536 
locAPIGnssNiResponse(uint32_t id,GnssNiResponse response)537 void LocationAPIClientBase::locAPIGnssNiResponse(uint32_t id, GnssNiResponse response)
538 {
539     uint32_t session = 0;
540     if (mLocationAPI) {
541         pthread_mutex_lock(&mMutex);
542         RequestQueue* requests = mRequestQueues[REQUEST_NIRESPONSE];
543         if (requests) {
544             delete requests;
545         }
546         uint32_t session = id;
547         mLocationAPI->gnssNiResponse(id, response);
548         LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
549         requests = new RequestQueue(session);
550         requests->push(new GnssNiResponseRequest(*this));
551         mRequestQueues[REQUEST_NIRESPONSE] = requests;
552         pthread_mutex_unlock(&mMutex);
553     }
554 }
555 
locAPIGnssDeleteAidingData(GnssAidingData & data)556 uint32_t LocationAPIClientBase::locAPIGnssDeleteAidingData(GnssAidingData& data)
557 {
558     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
559     if (mLocationControlAPI) {
560         pthread_mutex_lock(&mMutex);
561         RequestQueue* requests = mRequestQueues[REQUEST_DELETEAIDINGDATA];
562         if (requests) {
563             delete requests;
564         }
565         uint32_t session = mLocationControlAPI->gnssDeleteAidingData(data);
566         LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
567         requests = new RequestQueue(session);
568         requests->push(new GnssDeleteAidingDataRequest(*this));
569         mRequestQueues[REQUEST_DELETEAIDINGDATA] = requests;
570         pthread_mutex_unlock(&mMutex);
571 
572         retVal = LOCATION_ERROR_SUCCESS;
573     }
574 
575     return retVal;
576 }
577 
locAPIEnable(LocationTechnologyType techType)578 uint32_t LocationAPIClientBase::locAPIEnable(LocationTechnologyType techType)
579 {
580     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
581     if (mLocationControlAPI) {
582         pthread_mutex_lock(&mMutex);
583         RequestQueue* requests = mRequestQueues[REQUEST_CONTROL];
584         if (requests) {
585             delete requests;
586         }
587         uint32_t session = mLocationControlAPI->enable(techType);
588         LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
589         requests = new RequestQueue(session);
590         requests->push(new EnableRequest(*this));
591         mRequestQueues[REQUEST_CONTROL] = requests;
592         pthread_mutex_unlock(&mMutex);
593 
594         retVal = LOCATION_ERROR_SUCCESS;
595     }
596 
597     return retVal;
598 }
599 
locAPIDisable()600 void LocationAPIClientBase::locAPIDisable()
601 {
602     if (mLocationControlAPI) {
603         pthread_mutex_lock(&mMutex);
604         uint32_t session = -1;
605         RequestQueue* requests = mRequestQueues[REQUEST_CONTROL];
606         if (requests) {
607             session = requests->getSession();
608             requests->push(new DisableRequest(*this));
609             mLocationControlAPI->disable(session);
610         }
611         pthread_mutex_unlock(&mMutex);
612     }
613 }
614 
locAPIGnssUpdateConfig(GnssConfig config)615 uint32_t LocationAPIClientBase::locAPIGnssUpdateConfig(GnssConfig config)
616 {
617     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
618     if (memcmp(&mConfig, &config, sizeof(GnssConfig)) == 0) {
619         LOC_LOGE("%s:%d] GnssConfig is identical to previous call", __FUNCTION__, __LINE__);
620         return retVal;
621     }
622 
623     if (mLocationControlAPI) {
624         pthread_mutex_lock(&mMutex);
625 
626         memcpy(&mConfig, &config, sizeof(GnssConfig));
627 
628         uint32_t session = -1;
629         RequestQueue* requests = mRequestQueues[REQUEST_CONTROL];
630         if (requests) {
631             session = requests->getSession();
632             requests->push(new GnssUpdateConfigRequest(*this));
633             uint32_t* idArray = mLocationControlAPI->gnssUpdateConfig(config);
634             LOC_LOGV("%s:%d] gnssUpdateConfig return array: %p", __FUNCTION__, __LINE__, idArray);
635         }
636         pthread_mutex_unlock(&mMutex);
637 
638         retVal = LOCATION_ERROR_SUCCESS;
639     }
640     return retVal;
641 }
642 
beforeGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification)643 void LocationAPIClientBase::beforeGeofenceBreachCb(
644         GeofenceBreachNotification geofenceBreachNotification)
645 {
646     if (mGeofenceBreachCallback == nullptr)
647         return;
648     uint32_t* ids = (uint32_t*)malloc(sizeof(uint32_t) * geofenceBreachNotification.count);
649     uint32_t* backup = geofenceBreachNotification.ids;
650     size_t n = geofenceBreachNotification.count;
651 
652     size_t count = 0;
653     for (size_t i = 0; i < n; i++) {
654         uint32_t id = mGeofenceBiDict.getId(geofenceBreachNotification.ids[i]);
655         GeofenceBreachTypeMask type = mGeofenceBiDict.getType(geofenceBreachNotification.ids[i]);
656         if ((geofenceBreachNotification.type == GEOFENCE_BREACH_ENTER &&
657             (type & GEOFENCE_BREACH_ENTER_BIT)) ||
658             (geofenceBreachNotification.type == GEOFENCE_BREACH_EXIT &&
659             (type & GEOFENCE_BREACH_EXIT_BIT))
660            ) {
661             ids[count] = id;
662             count++;
663         }
664     }
665     geofenceBreachNotification.count = count;
666     geofenceBreachNotification.ids = ids;
667     mGeofenceBreachCallback(geofenceBreachNotification);
668 
669     // restore ids
670     geofenceBreachNotification.ids = backup;
671     geofenceBreachNotification.count = n;
672     free(ids);
673 }
674 
onResponseCb(LocationError error,uint32_t id)675 void LocationAPIClientBase::onResponseCb(LocationError error, uint32_t id)
676 {
677     if (error != LOCATION_ERROR_SUCCESS) {
678         LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, error, id);
679     } else {
680         LOC_LOGV("%s:%d] error: %d id: %d", __FUNCTION__, __LINE__, error, id);
681     }
682     LocationAPIRequest* request = getRequestBySession(id);
683     if (request) {
684         request->onResponse(error);
685         delete request;
686     }
687 }
688 
onCollectiveResponseCb(size_t count,LocationError * errors,uint32_t * ids)689 void LocationAPIClientBase::onCollectiveResponseCb(
690         size_t count, LocationError* errors, uint32_t* ids)
691 {
692     for (size_t i = 0; i < count; i++) {
693         if (errors[i] != LOCATION_ERROR_SUCCESS) {
694             LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
695         } else {
696             LOC_LOGV("%s:%d] error: %d id: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
697         }
698     }
699     LocationAPIRequest* request = nullptr;
700     if (count > 0 && ids)
701         request = getRequestBySession(ids[0]);
702     if (!request)
703         request = getGeofencesRequest();
704     if (request) {
705         request->onCollectiveResponse(count, errors, ids);
706         delete request;
707     }
708 }
709 
onCtrlResponseCb(LocationError error,uint32_t id)710 void LocationAPIClientBase::onCtrlResponseCb(LocationError error, uint32_t id)
711 {
712     if (error != LOCATION_ERROR_SUCCESS) {
713         LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, error, id);
714     } else {
715         LOC_LOGV("%s:%d] error: %d id: %d", __FUNCTION__, __LINE__, error, id);
716     }
717     LocationAPIRequest* request = getRequestBySession(id);
718     if (request) {
719         request->onResponse(error);
720         delete request;
721     }
722 }
723 
onCtrlCollectiveResponseCb(size_t count,LocationError * errors,uint32_t * ids)724 void LocationAPIClientBase::onCtrlCollectiveResponseCb(
725         size_t count, LocationError* errors, uint32_t* ids)
726 {
727     for (size_t i = 0; i < count; i++) {
728         if (errors[i] != LOCATION_ERROR_SUCCESS) {
729             LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
730         } else {
731             LOC_LOGV("%s:%d] error: %d id: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
732         }
733     }
734     LocationAPIRequest* request = nullptr;
735     if (count > 0 && ids)
736         request = getRequestBySession(ids[0]);
737     if (request) {
738         request->onCollectiveResponse(count, errors, ids);
739         delete request;
740     }
741 }
742 
743 LocationAPIClientBase::LocationAPIRequest*
getRequestBySession(uint32_t session)744 LocationAPIClientBase::getRequestBySession(uint32_t session)
745 {
746     pthread_mutex_lock(&mMutex);
747     LocationAPIRequest* request = nullptr;
748     for (int i = 0; i < REQUEST_MAX; i++) {
749         if (i != REQUEST_GEOFENCE &&
750                 mRequestQueues[i] &&
751                 mRequestQueues[i]->getSession() == session) {
752             request = mRequestQueues[i]->pop();
753             break;
754         }
755     }
756     pthread_mutex_unlock(&mMutex);
757     return request;
758 }
759 
760 LocationAPIClientBase::LocationAPIRequest*
getGeofencesRequest()761 LocationAPIClientBase::getGeofencesRequest()
762 {
763     pthread_mutex_lock(&mMutex);
764     LocationAPIRequest* request = nullptr;
765     if (mRequestQueues[REQUEST_GEOFENCE]) {
766         request = mRequestQueues[REQUEST_GEOFENCE]->pop();
767     }
768     pthread_mutex_unlock(&mMutex);
769     return request;
770 }
771