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_NDEBUG 0
30 #define LOG_TAG "LocSvc_APIClientBase"
31 
32 #include <loc_pla.h>
33 #include <log_util.h>
34 #include <inttypes.h>
35 #include <loc_cfg.h>
36 #include "LocationAPIClientBase.h"
37 
38 #define GEOFENCE_SESSION_ID 0xFFFFFFFF
39 #define CONFIG_SESSION_ID 0xFFFFFFFF
40 
41 // LocationAPIControlClient
LocationAPIControlClient()42 LocationAPIControlClient::LocationAPIControlClient() :
43     mEnabled(false)
44 {
45     pthread_mutex_init(&mMutex, nullptr);
46 
47     for (int i = 0; i < CTRL_REQUEST_MAX; i++) {
48         mRequestQueues[i].reset((uint32_t)0);
49     }
50 
51     memset(&mConfig, 0, sizeof(GnssConfig));
52 
53     LocationControlCallbacks locationControlCallbacks;
54     locationControlCallbacks.size = sizeof(LocationControlCallbacks);
55 
56     locationControlCallbacks.responseCb =
57         [this](LocationError error, uint32_t id) {
58             onCtrlResponseCb(error, id);
59         };
60     locationControlCallbacks.collectiveResponseCb =
61         [this](size_t count, LocationError* errors, uint32_t* ids) {
62             onCtrlCollectiveResponseCb(count, errors, ids);
63         };
64 
65     mLocationControlAPI = LocationControlAPI::createInstance(locationControlCallbacks);
66 }
67 
~LocationAPIControlClient()68 LocationAPIControlClient::~LocationAPIControlClient()
69 {
70     pthread_mutex_lock(&mMutex);
71 
72     if (mLocationControlAPI) {
73         mLocationControlAPI->destroy();
74         mLocationControlAPI = nullptr;
75     }
76 
77     for (int i = 0; i < CTRL_REQUEST_MAX; i++) {
78         mRequestQueues[i].reset((uint32_t)0);
79     }
80 
81     pthread_mutex_unlock(&mMutex);
82 
83     pthread_mutex_destroy(&mMutex);
84 }
85 
locAPIGnssDeleteAidingData(GnssAidingData & data)86 uint32_t LocationAPIControlClient::locAPIGnssDeleteAidingData(GnssAidingData& data)
87 {
88     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
89     pthread_mutex_lock(&mMutex);
90     if (mLocationControlAPI) {
91         uint32_t session = mLocationControlAPI->gnssDeleteAidingData(data);
92         LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
93         mRequestQueues[CTRL_REQUEST_DELETEAIDINGDATA].reset(session);
94         mRequestQueues[CTRL_REQUEST_DELETEAIDINGDATA].push(new GnssDeleteAidingDataRequest(*this));
95 
96         retVal = LOCATION_ERROR_SUCCESS;
97     }
98     pthread_mutex_unlock(&mMutex);
99 
100     return retVal;
101 }
102 
locAPIEnable(LocationTechnologyType techType)103 uint32_t LocationAPIControlClient::locAPIEnable(LocationTechnologyType techType)
104 {
105     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
106     pthread_mutex_lock(&mMutex);
107     if (mEnabled) {
108         // just return success if already enabled
109         retVal = LOCATION_ERROR_SUCCESS;
110     } else if (mLocationControlAPI) {
111         uint32_t session = mLocationControlAPI->enable(techType);
112         LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
113         mRequestQueues[CTRL_REQUEST_CONTROL].reset(session);
114         mRequestQueues[CTRL_REQUEST_CONTROL].push(new EnableRequest(*this));
115         retVal = LOCATION_ERROR_SUCCESS;
116         mEnabled = true;
117     } else {
118         LOC_LOGE("%s:%d] failed.", __FUNCTION__, __LINE__);
119     }
120     pthread_mutex_unlock(&mMutex);
121 
122     return retVal;
123 }
124 
locAPIDisable()125 void LocationAPIControlClient::locAPIDisable()
126 {
127     pthread_mutex_lock(&mMutex);
128     if (mEnabled && mLocationControlAPI) {
129         uint32_t session = 0;
130         session = mRequestQueues[CTRL_REQUEST_CONTROL].getSession();
131         if (session > 0) {
132             mRequestQueues[CTRL_REQUEST_CONTROL].push(new DisableRequest(*this));
133             mLocationControlAPI->disable(session);
134             mEnabled = false;
135         } else {
136             LOC_LOGE("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__, session);
137         }
138     }
139     pthread_mutex_unlock(&mMutex);
140 }
141 
locAPIGnssUpdateConfig(GnssConfig config)142 uint32_t LocationAPIControlClient::locAPIGnssUpdateConfig(GnssConfig config)
143 {
144     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
145 
146     pthread_mutex_lock(&mMutex);
147     if (mLocationControlAPI) {
148         if (mConfig.equals(config)) {
149             LOC_LOGv("GnssConfig is identical to previous call");
150             retVal = LOCATION_ERROR_SUCCESS;
151         } else {
152             mConfig = config;
153             uint32_t* idArray = mLocationControlAPI->gnssUpdateConfig(config);
154             LOC_LOGv("gnssUpdateConfig return array: %p", idArray);
155             if (nullptr != idArray) {
156                 if (nullptr != mRequestQueues[CTRL_REQUEST_CONFIG_UPDATE].getSessionArrayPtr()) {
157                     mRequestQueues[CTRL_REQUEST_CONFIG_UPDATE].reset(idArray);
158                 }
159                 mRequestQueues[CTRL_REQUEST_CONFIG_UPDATE].push(new GnssUpdateConfigRequest(*this));
160                 retVal = LOCATION_ERROR_SUCCESS;
161             }
162         }
163     }
164     pthread_mutex_unlock(&mMutex);
165     return retVal;
166 }
167 
locAPIGnssGetConfig(GnssConfigFlagsMask mask)168 uint32_t LocationAPIControlClient::locAPIGnssGetConfig(GnssConfigFlagsMask mask)
169 {
170     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
171 
172     pthread_mutex_lock(&mMutex);
173     if (mLocationControlAPI) {
174 
175         uint32_t* idArray = mLocationControlAPI->gnssGetConfig(mask);
176         LOC_LOGv("gnssGetConfig return array: %p", idArray);
177         if (nullptr != idArray) {
178             if (nullptr != mRequestQueues[CTRL_REQUEST_CONFIG_GET].getSessionArrayPtr()) {
179                 mRequestQueues[CTRL_REQUEST_CONFIG_GET].reset(idArray);
180             }
181             mRequestQueues[CTRL_REQUEST_CONFIG_GET].push(new GnssGetConfigRequest(*this));
182             retVal = LOCATION_ERROR_SUCCESS;
183         }
184     }
185     pthread_mutex_unlock(&mMutex);
186     return retVal;
187 }
188 
onCtrlResponseCb(LocationError error,uint32_t id)189 void LocationAPIControlClient::onCtrlResponseCb(LocationError error, uint32_t id)
190 {
191     if (error != LOCATION_ERROR_SUCCESS) {
192         LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, error, id);
193     } else {
194         LOC_LOGV("%s:%d] SUCCESS: %d id: %d", __FUNCTION__, __LINE__, error, id);
195     }
196     LocationAPIRequest* request = getRequestBySession(id);
197     if (request) {
198         request->onResponse(error, id);
199         delete request;
200     }
201 }
202 
onCtrlCollectiveResponseCb(size_t count,LocationError * errors,uint32_t * ids)203 void LocationAPIControlClient::onCtrlCollectiveResponseCb(
204         size_t count, LocationError* errors, uint32_t* ids)
205 {
206     for (size_t i = 0; i < count; i++) {
207         if (errors[i] != LOCATION_ERROR_SUCCESS) {
208             LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
209         } else {
210             LOC_LOGV("%s:%d] SUCCESS: %d id: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
211         }
212     }
213     LocationAPIRequest* request = getRequestBySessionArrayPtr(ids);
214     if (request) {
215         request->onCollectiveResponse(count, errors, ids);
216         delete request;
217     }
218 }
219 
getRequestBySession(uint32_t session)220 LocationAPIRequest* LocationAPIControlClient::getRequestBySession(uint32_t session)
221 {
222     pthread_mutex_lock(&mMutex);
223     LocationAPIRequest* request = nullptr;
224 
225     if (mRequestQueues[CTRL_REQUEST_DELETEAIDINGDATA].getSession() == session) {
226         request = mRequestQueues[CTRL_REQUEST_DELETEAIDINGDATA].pop();
227     } else if (mRequestQueues[CTRL_REQUEST_CONTROL].getSession() == session) {
228         request = mRequestQueues[CTRL_REQUEST_CONTROL].pop();
229     }
230 
231     pthread_mutex_unlock(&mMutex);
232     return request;
233 }
234 
235 LocationAPIRequest*
getRequestBySessionArrayPtr(uint32_t * sessionArrayPtr)236 LocationAPIControlClient::getRequestBySessionArrayPtr(
237         uint32_t* sessionArrayPtr)
238 {
239     pthread_mutex_lock(&mMutex);
240     LocationAPIRequest* request = nullptr;
241 
242     if (mRequestQueues[CTRL_REQUEST_CONFIG_UPDATE].getSessionArrayPtr() == sessionArrayPtr) {
243         request = mRequestQueues[CTRL_REQUEST_CONFIG_UPDATE].pop();
244     } else if (mRequestQueues[CTRL_REQUEST_CONFIG_GET].getSessionArrayPtr() == sessionArrayPtr) {
245         request = mRequestQueues[CTRL_REQUEST_CONFIG_GET].pop();
246     }
247 
248     pthread_mutex_unlock(&mMutex);
249     return request;
250 }
251 
252 // LocationAPIClientBase
LocationAPIClientBase()253 LocationAPIClientBase::LocationAPIClientBase() :
254     mGeofenceBreachCallback(nullptr),
255     mBatchingStatusCallback(nullptr),
256     mLocationAPI(nullptr),
257     mBatchSize(-1),
258     mTracking(false)
259 {
260 
261     // use recursive mutex, in case callback come from the same thread
262     pthread_mutexattr_t attr;
263     pthread_mutexattr_init(&attr);
264     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
265     pthread_mutex_init(&mMutex, &attr);
266 
267     for (int i = 0; i < REQUEST_MAX; i++) {
268         mRequestQueues[i].reset((uint32_t)0);
269     }
270 }
271 
locAPISetCallbacks(LocationCallbacks & locationCallbacks)272 void LocationAPIClientBase::locAPISetCallbacks(LocationCallbacks& locationCallbacks)
273 {
274     pthread_mutex_lock(&mMutex);
275 
276     if (locationCallbacks.geofenceBreachCb != nullptr) {
277         mGeofenceBreachCallback = locationCallbacks.geofenceBreachCb;
278         locationCallbacks.geofenceBreachCb =
279             [this](GeofenceBreachNotification geofenceBreachNotification) {
280                 beforeGeofenceBreachCb(geofenceBreachNotification);
281             };
282     }
283 
284     locationCallbacks.capabilitiesCb =
285         [this](LocationCapabilitiesMask capabilitiesMask) {
286             onCapabilitiesCb(capabilitiesMask);
287         };
288     locationCallbacks.responseCb = [this](LocationError error, uint32_t id) {
289         onResponseCb(error, id);
290     };
291     locationCallbacks.collectiveResponseCb =
292         [this](size_t count, LocationError* errors, uint32_t* ids) {
293             onCollectiveResponseCb(count, errors, ids);
294         };
295 
296     if (locationCallbacks.batchingStatusCb != nullptr) {
297         mBatchingStatusCallback = locationCallbacks.batchingStatusCb;
298         locationCallbacks.batchingStatusCb =
299             [this](BatchingStatusInfo batchStatus, std::list<uint32_t> & tripCompletedList) {
300             beforeBatchingStatusCb(batchStatus, tripCompletedList);
301         };
302     }
303 
304     if (mLocationAPI == nullptr ) {
305         mLocationAPI = LocationAPI::createInstance(locationCallbacks);
306     } else {
307         mLocationAPI->updateCallbacks(locationCallbacks);
308     }
309 
310     pthread_mutex_unlock(&mMutex);
311 }
312 
~LocationAPIClientBase()313 LocationAPIClientBase::~LocationAPIClientBase()
314 {
315     pthread_mutex_lock(&mMutex);
316 
317     mGeofenceBreachCallback = nullptr;
318 
319     if (mLocationAPI) {
320         mLocationAPI->destroy();
321         mLocationAPI = nullptr;
322     }
323 
324     for (int i = 0; i < REQUEST_MAX; i++) {
325         mRequestQueues[i].reset((uint32_t)0);
326     }
327 
328     pthread_mutex_unlock(&mMutex);
329 
330     pthread_mutex_destroy(&mMutex);
331 }
332 
locAPIStartTracking(TrackingOptions & options)333 uint32_t LocationAPIClientBase::locAPIStartTracking(TrackingOptions& options)
334 {
335     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
336     pthread_mutex_lock(&mMutex);
337     if (mLocationAPI) {
338         if (mTracking) {
339             LOC_LOGW("%s:%d] Existing tracking session present", __FUNCTION__, __LINE__);
340         } else {
341             uint32_t session = mLocationAPI->startTracking(options);
342             LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
343             // onResponseCb might be called from other thread immediately after
344             // startTracking returns, so we are not going to unlock mutex
345             // until StartTrackingRequest is pushed into mRequestQueues[REQUEST_TRACKING]
346             mRequestQueues[REQUEST_TRACKING].reset(session);
347             mRequestQueues[REQUEST_TRACKING].push(new StartTrackingRequest(*this));
348             mTracking = true;
349         }
350 
351         retVal = LOCATION_ERROR_SUCCESS;
352     }
353     pthread_mutex_unlock(&mMutex);
354 
355     return retVal;
356 }
357 
locAPIStopTracking()358 void LocationAPIClientBase::locAPIStopTracking()
359 {
360     pthread_mutex_lock(&mMutex);
361     if (mLocationAPI) {
362         uint32_t session = 0;
363         session = mRequestQueues[REQUEST_TRACKING].getSession();
364         if (session > 0) {
365             mRequestQueues[REQUEST_TRACKING].push(new StopTrackingRequest(*this));
366             mLocationAPI->stopTracking(session);
367             mTracking = false;
368         } else {
369             LOC_LOGD("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__, session);
370         }
371     }
372     pthread_mutex_unlock(&mMutex);
373 }
374 
locAPIUpdateTrackingOptions(TrackingOptions & options)375 void LocationAPIClientBase::locAPIUpdateTrackingOptions(TrackingOptions& options)
376 {
377     pthread_mutex_lock(&mMutex);
378     if (mLocationAPI) {
379         uint32_t session = 0;
380         session = mRequestQueues[REQUEST_TRACKING].getSession();
381         if (session > 0) {
382             mRequestQueues[REQUEST_TRACKING].push(new UpdateTrackingOptionsRequest(*this));
383             mLocationAPI->updateTrackingOptions(session, options);
384         } else {
385             LOC_LOGE("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__, session);
386         }
387     }
388     pthread_mutex_unlock(&mMutex);
389 }
390 
locAPIGetBatchSize()391 int32_t LocationAPIClientBase::locAPIGetBatchSize()
392 {
393     if (mBatchSize == -1) {
394         const loc_param_s_type flp_conf_param_table[] =
395         {
396             {"BATCH_SIZE", &mBatchSize, nullptr, 'n'},
397         };
398         UTIL_READ_CONF(LOC_PATH_FLP_CONF, flp_conf_param_table);
399         if (mBatchSize < 0) {
400             // set mBatchSize to 0 if we got an illegal value from config file
401             mBatchSize = 0;
402         }
403     }
404     return mBatchSize;
405 }
406 
locAPIStartSession(uint32_t id,uint32_t sessionMode,TrackingOptions && options)407 uint32_t LocationAPIClientBase::locAPIStartSession(
408         uint32_t id, uint32_t sessionMode, TrackingOptions&& options)
409 {
410     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
411     pthread_mutex_lock(&mMutex);
412     if (mLocationAPI) {
413 
414         if (mSessionBiDict.hasId(id)) {
415             LOC_LOGE("%s:%d] session %d has already started.", __FUNCTION__, __LINE__, id);
416             retVal = LOCATION_ERROR_ALREADY_STARTED;
417         } else {
418             uint32_t trackingSession = 0;
419             uint32_t batchingSession = 0;
420 
421             if (sessionMode == SESSION_MODE_ON_FIX) {
422                 trackingSession = mLocationAPI->startTracking(options);
423                 LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, trackingSession);
424                 mRequestQueues[REQUEST_SESSION].push(new StartTrackingRequest(*this));
425             } else {
426                 // Fill in the batch mode
427                 BatchingOptions batchOptions = {};
428                 batchOptions.size = sizeof(BatchingOptions);
429                 switch (sessionMode) {
430                 case SESSION_MODE_ON_FULL:
431                     batchOptions.batchingMode = BATCHING_MODE_ROUTINE;
432                     break;
433                 case SESSION_MODE_ON_TRIP_COMPLETED:
434                     batchOptions.batchingMode = BATCHING_MODE_TRIP;
435                     break;
436                 default:
437                     batchOptions.batchingMode = BATCHING_MODE_NO_AUTO_REPORT;
438                     break;
439                 }
440 
441                 // Populate location option values
442                 batchOptions.minDistance = options.minDistance;
443                 batchOptions.minInterval = options.minInterval;
444                 batchOptions.mode = options.mode;
445 
446                 batchingSession = mLocationAPI->startBatching(batchOptions);
447                 LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, batchingSession);
448                 mRequestQueues[REQUEST_SESSION].setSession(batchingSession);
449                 mRequestQueues[REQUEST_SESSION].push(new StartBatchingRequest(*this));
450             }
451 
452             uint32_t session = ((sessionMode != SESSION_MODE_ON_FIX) ?
453                     batchingSession : trackingSession);
454 
455             SessionEntity entity;
456             entity.id = id;
457             entity.trackingSession = trackingSession;
458             entity.batchingSession = batchingSession;
459             entity.sessionMode = sessionMode;
460             mSessionBiDict.set(id, session, entity);
461 
462             retVal = LOCATION_ERROR_SUCCESS;
463         }
464 
465     }
466     pthread_mutex_unlock(&mMutex);
467 
468     return retVal;
469 }
470 
locAPIStopSession(uint32_t id)471 uint32_t LocationAPIClientBase::locAPIStopSession(uint32_t id)
472 {
473     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
474     pthread_mutex_lock(&mMutex);
475     if (mLocationAPI) {
476 
477         if (mSessionBiDict.hasId(id)) {
478             SessionEntity entity = mSessionBiDict.getExtById(id);
479 
480             uint32_t trackingSession = entity.trackingSession;
481             uint32_t batchingSession = entity.batchingSession;
482             uint32_t sMode = entity.sessionMode;
483 
484             if (sMode == SESSION_MODE_ON_FIX) {
485                 mRequestQueues[REQUEST_SESSION].push(new StopTrackingRequest(*this));
486                 mLocationAPI->stopTracking(trackingSession);
487             } else {
488                 mRequestQueues[REQUEST_SESSION].push(new StopBatchingRequest(*this));
489                 mLocationAPI->stopBatching(batchingSession);
490             }
491 
492             retVal = LOCATION_ERROR_SUCCESS;
493         } else {
494             retVal = LOCATION_ERROR_ID_UNKNOWN;
495             LOC_LOGE("%s:%d] session %d is not exist.", __FUNCTION__, __LINE__, id);
496         }
497 
498     }
499     pthread_mutex_unlock(&mMutex);
500     return retVal;
501 }
502 
locAPIUpdateSessionOptions(uint32_t id,uint32_t sessionMode,TrackingOptions && options)503 uint32_t LocationAPIClientBase::locAPIUpdateSessionOptions(
504         uint32_t id, uint32_t sessionMode, TrackingOptions&& options)
505 {
506     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
507     pthread_mutex_lock(&mMutex);
508     if (mLocationAPI) {
509 
510         if (mSessionBiDict.hasId(id)) {
511             SessionEntity entity = mSessionBiDict.getExtById(id);
512 
513             uint32_t trackingSession = entity.trackingSession;
514             uint32_t batchingSession = entity.batchingSession;
515             uint32_t sMode = entity.sessionMode;
516 
517             if (sessionMode == SESSION_MODE_ON_FIX) {
518                 // we only add an UpdateTrackingOptionsRequest to mRequestQueues[REQUEST_SESSION],
519                 // even if this update request will stop batching and then start tracking.
520                 mRequestQueues[REQUEST_SESSION].push(new UpdateTrackingOptionsRequest(*this));
521                 if (sMode == SESSION_MODE_ON_FIX) {
522                     mLocationAPI->updateTrackingOptions(trackingSession, options);
523                 } else  {
524                     // stop batching
525                     // batchingSession will be removed from mSessionBiDict soon,
526                     // so we don't need to add a new request to mRequestQueues[REQUEST_SESSION].
527                     mLocationAPI->stopBatching(batchingSession);
528                     batchingSession = 0;
529                     mRequestQueues[REQUEST_SESSION].setSession(batchingSession);
530 
531                     // start tracking
532                     trackingSession = mLocationAPI->startTracking(options);
533                     LOC_LOGI("%s:%d] start new session: %d",
534                             __FUNCTION__, __LINE__, trackingSession);
535                 }
536             } else {
537                 // we only add an UpdateBatchingOptionsRequest to mRequestQueues[REQUEST_SESSION],
538                 // even if this update request will stop tracking and then start batching.
539                 mRequestQueues[REQUEST_SESSION].push(new UpdateBatchingOptionsRequest(*this));
540                 BatchingOptions batchOptions = {};
541                 batchOptions.size = sizeof(BatchingOptions);
542                 switch (sessionMode) {
543                 case SESSION_MODE_ON_FULL:
544                     batchOptions.batchingMode = BATCHING_MODE_ROUTINE;
545                     break;
546                 case SESSION_MODE_ON_TRIP_COMPLETED:
547                     batchOptions.batchingMode = BATCHING_MODE_TRIP;
548                     break;
549                 default:
550                     batchOptions.batchingMode = BATCHING_MODE_NO_AUTO_REPORT;
551                     break;
552                 }
553 
554                 if (sMode == SESSION_MODE_ON_FIX) {
555                     // stop tracking
556                     // trackingSession will be removed from mSessionBiDict soon,
557                     // so we don't need to add a new request to mRequestQueues[REQUEST_SESSION].
558                     mLocationAPI->stopTracking(trackingSession);
559                     trackingSession = 0;
560 
561                     // Populate location option values
562                     batchOptions.minDistance = options.minDistance;
563                     batchOptions.minInterval = options.minInterval;
564                     batchOptions.mode = options.mode;
565 
566                     // start batching
567                     batchingSession = mLocationAPI->startBatching(batchOptions);
568                     LOC_LOGI("%s:%d] start new session: %d",
569                             __FUNCTION__, __LINE__, batchingSession);
570                     mRequestQueues[REQUEST_SESSION].setSession(batchingSession);
571                 } else {
572                     mLocationAPI->updateBatchingOptions(batchingSession, batchOptions);
573                 }
574 
575             }
576 
577             uint32_t session = ((sessionMode != SESSION_MODE_ON_FIX) ?
578                     batchingSession : trackingSession);
579 
580             entity.trackingSession = trackingSession;
581             entity.batchingSession = batchingSession;
582             entity.sessionMode = sessionMode;
583             // remove the old values from mSessionBiDict before we add a new one.
584             mSessionBiDict.rmById(id);
585             mSessionBiDict.set(id, session, entity);
586 
587             retVal = LOCATION_ERROR_SUCCESS;
588         } else {
589             retVal = LOCATION_ERROR_ID_UNKNOWN;
590             LOC_LOGE("%s:%d] session %d is not exist.", __FUNCTION__, __LINE__, id);
591         }
592     }
593     pthread_mutex_unlock(&mMutex);
594     return retVal;
595 }
596 
locAPIGetBatchedLocations(uint32_t id,size_t count)597 uint32_t LocationAPIClientBase::locAPIGetBatchedLocations(uint32_t id, size_t count)
598 {
599     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
600     pthread_mutex_lock(&mMutex);
601     if (mLocationAPI) {
602         if (mSessionBiDict.hasId(id)) {
603             SessionEntity entity = mSessionBiDict.getExtById(id);
604             if (entity.sessionMode != SESSION_MODE_ON_FIX) {
605                 uint32_t batchingSession = entity.batchingSession;
606                 mRequestQueues[REQUEST_SESSION].push(new GetBatchedLocationsRequest(*this));
607                 mLocationAPI->getBatchedLocations(batchingSession, count);
608                 retVal = LOCATION_ERROR_SUCCESS;
609             }  else {
610                 LOC_LOGE("%s:%d] Unsupported for session id: %d, mode is SESSION_MODE_ON_FIX",
611                             __FUNCTION__, __LINE__, id);
612                 retVal = LOCATION_ERROR_NOT_SUPPORTED;
613             }
614         }  else {
615             retVal = LOCATION_ERROR_ID_UNKNOWN;
616             LOC_LOGE("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__, id);
617         }
618     }
619     pthread_mutex_unlock(&mMutex);
620 
621     return retVal;
622 }
623 
locAPIAddGeofences(size_t count,uint32_t * ids,GeofenceOption * options,GeofenceInfo * data)624 uint32_t LocationAPIClientBase::locAPIAddGeofences(
625         size_t count, uint32_t* ids, GeofenceOption* options, GeofenceInfo* data)
626 {
627     uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
628     pthread_mutex_lock(&mMutex);
629     if (mLocationAPI) {
630         if (mRequestQueues[REQUEST_GEOFENCE].getSession() != GEOFENCE_SESSION_ID) {
631             mRequestQueues[REQUEST_GEOFENCE].reset(GEOFENCE_SESSION_ID);
632         }
633         uint32_t* sessions = mLocationAPI->addGeofences(count, options, data);
634         if (sessions) {
635             LOC_LOGI("%s:%d] start new sessions: %p", __FUNCTION__, __LINE__, sessions);
636             mRequestQueues[REQUEST_GEOFENCE].push(new AddGeofencesRequest(*this));
637 
638             for (size_t i = 0; i < count; i++) {
639                 mGeofenceBiDict.set(ids[i], sessions[i], options[i].breachTypeMask);
640             }
641             retVal = LOCATION_ERROR_SUCCESS;
642         }
643     }
644     pthread_mutex_unlock(&mMutex);
645 
646     return retVal;
647 }
648 
locAPIRemoveGeofences(size_t count,uint32_t * ids)649 void LocationAPIClientBase::locAPIRemoveGeofences(size_t count, uint32_t* ids)
650 {
651     pthread_mutex_lock(&mMutex);
652     if (mLocationAPI) {
653         uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
654         if (sessions == NULL) {
655             LOC_LOGE("%s:%d] Failed to allocate %zu bytes !",
656                     __FUNCTION__, __LINE__, sizeof(uint32_t) * count);
657             pthread_mutex_unlock(&mMutex);
658             return;
659         }
660 
661         if (mRequestQueues[REQUEST_GEOFENCE].getSession() == GEOFENCE_SESSION_ID) {
662             BiDict<GeofenceBreachTypeMask>* removedGeofenceBiDict =
663                     new BiDict<GeofenceBreachTypeMask>();
664             size_t j = 0;
665             for (size_t i = 0; i < count; i++) {
666                 sessions[j] = mGeofenceBiDict.getSession(ids[i]);
667                 if (sessions[j] > 0) {
668                     GeofenceBreachTypeMask type = mGeofenceBiDict.getExtBySession(sessions[j]);
669                     mGeofenceBiDict.rmBySession(sessions[j]);
670                     removedGeofenceBiDict->set(ids[i], sessions[j], type);
671                     j++;
672                 }
673             }
674             if (j > 0) {
675                 mRequestQueues[REQUEST_GEOFENCE].push(new RemoveGeofencesRequest(*this,
676                         removedGeofenceBiDict));
677                 mLocationAPI->removeGeofences(j, sessions);
678             } else {
679                 delete(removedGeofenceBiDict);
680             }
681         } else {
682             LOC_LOGE("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__,
683                     mRequestQueues[REQUEST_GEOFENCE].getSession());
684         }
685 
686         free(sessions);
687     }
688     pthread_mutex_unlock(&mMutex);
689 }
690 
locAPIModifyGeofences(size_t count,uint32_t * ids,GeofenceOption * options)691 void LocationAPIClientBase::locAPIModifyGeofences(
692         size_t count, uint32_t* ids, GeofenceOption* options)
693 {
694     pthread_mutex_lock(&mMutex);
695     if (mLocationAPI) {
696         uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
697         if (sessions == NULL) {
698             LOC_LOGE("%s:%d] Failed to allocate %zu bytes !",
699                     __FUNCTION__, __LINE__, sizeof(uint32_t) * count);
700             pthread_mutex_unlock(&mMutex);
701             return;
702         }
703 
704         if (mRequestQueues[REQUEST_GEOFENCE].getSession() == GEOFENCE_SESSION_ID) {
705             size_t j = 0;
706             for (size_t i = 0; i < count; i++) {
707                 sessions[j] = mGeofenceBiDict.getSession(ids[i]);
708                 if (sessions[j] > 0) {
709                     mGeofenceBiDict.set(ids[i], sessions[j], options[i].breachTypeMask);
710                     j++;
711                 }
712             }
713             if (j > 0) {
714                 mRequestQueues[REQUEST_GEOFENCE].push(new ModifyGeofencesRequest(*this));
715                 mLocationAPI->modifyGeofences(j, sessions, options);
716             }
717         } else {
718             LOC_LOGE("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__,
719                     mRequestQueues[REQUEST_GEOFENCE].getSession());
720         }
721 
722         free(sessions);
723     }
724     pthread_mutex_unlock(&mMutex);
725 }
726 
locAPIPauseGeofences(size_t count,uint32_t * ids)727 void LocationAPIClientBase::locAPIPauseGeofences(size_t count, uint32_t* ids)
728 {
729     pthread_mutex_lock(&mMutex);
730     if (mLocationAPI) {
731         uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
732         if (sessions == NULL) {
733             LOC_LOGE("%s:%d] Failed to allocate %zu bytes !",
734                     __FUNCTION__, __LINE__, sizeof(uint32_t) * count);
735             pthread_mutex_unlock(&mMutex);
736             return;
737         }
738 
739         if (mRequestQueues[REQUEST_GEOFENCE].getSession() == GEOFENCE_SESSION_ID) {
740             size_t j = 0;
741             for (size_t i = 0; i < count; i++) {
742                 sessions[j] = mGeofenceBiDict.getSession(ids[i]);
743                 if (sessions[j] > 0) {
744                     j++;
745                 }
746             }
747             if (j > 0) {
748                 mRequestQueues[REQUEST_GEOFENCE].push(new PauseGeofencesRequest(*this));
749                 mLocationAPI->pauseGeofences(j, sessions);
750             }
751         } else {
752             LOC_LOGE("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__,
753                     mRequestQueues[REQUEST_GEOFENCE].getSession());
754         }
755 
756         free(sessions);
757     }
758     pthread_mutex_unlock(&mMutex);
759 }
760 
locAPIResumeGeofences(size_t count,uint32_t * ids,GeofenceBreachTypeMask * mask)761 void LocationAPIClientBase::locAPIResumeGeofences(
762         size_t count, uint32_t* ids, GeofenceBreachTypeMask* mask)
763 {
764     pthread_mutex_lock(&mMutex);
765     if (mLocationAPI) {
766         uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
767         if (sessions == NULL) {
768             LOC_LOGE("%s:%d] Failed to allocate %zu bytes !",
769                     __FUNCTION__, __LINE__, sizeof(uint32_t) * count);
770             pthread_mutex_unlock(&mMutex);
771             return;
772         }
773 
774         if (mRequestQueues[REQUEST_GEOFENCE].getSession() == GEOFENCE_SESSION_ID) {
775             size_t j = 0;
776             for (size_t i = 0; i < count; i++) {
777                 sessions[j] = mGeofenceBiDict.getSession(ids[i]);
778                 if (sessions[j] > 0) {
779                     if (mask) {
780                         mGeofenceBiDict.set(ids[i], sessions[j], mask[i]);
781                     }
782                     j++;
783                 }
784             }
785             if (j > 0) {
786                 mRequestQueues[REQUEST_GEOFENCE].push(new ResumeGeofencesRequest(*this));
787                 mLocationAPI->resumeGeofences(j, sessions);
788             }
789         } else {
790             LOC_LOGE("%s:%d] invalid session: %d.", __FUNCTION__, __LINE__,
791                     mRequestQueues[REQUEST_GEOFENCE].getSession());
792         }
793 
794         free(sessions);
795     }
796     pthread_mutex_unlock(&mMutex);
797 }
798 
locAPIRemoveAllGeofences()799 void LocationAPIClientBase::locAPIRemoveAllGeofences()
800 {
801     std::vector<uint32_t> sessionsVec = mGeofenceBiDict.getAllSessions();
802     locAPIRemoveGeofences(sessionsVec.size(), &sessionsVec[0]);
803 }
804 
locAPIGnssNiResponse(uint32_t id,GnssNiResponse response)805 void LocationAPIClientBase::locAPIGnssNiResponse(uint32_t id, GnssNiResponse response)
806 {
807     pthread_mutex_lock(&mMutex);
808     if (mLocationAPI) {
809         uint32_t session = id;
810         mLocationAPI->gnssNiResponse(id, response);
811         LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
812         mRequestQueues[REQUEST_NIRESPONSE].reset(session);
813         mRequestQueues[REQUEST_NIRESPONSE].push(new GnssNiResponseRequest(*this));
814     }
815     pthread_mutex_unlock(&mMutex);
816 }
817 
beforeGeofenceBreachCb(GeofenceBreachNotification geofenceBreachNotification)818 void LocationAPIClientBase::beforeGeofenceBreachCb(
819         GeofenceBreachNotification geofenceBreachNotification)
820 {
821     uint32_t* ids = (uint32_t*)malloc(sizeof(uint32_t) * geofenceBreachNotification.count);
822     uint32_t* backup = geofenceBreachNotification.ids;
823     size_t n = geofenceBreachNotification.count;
824     geofenceBreachCallback genfenceCallback = nullptr;
825 
826     if (ids == NULL) {
827         LOC_LOGE("%s:%d] Failed to alloc %zu bytes",
828                 __FUNCTION__, __LINE__,
829                 sizeof(uint32_t) * geofenceBreachNotification.count);
830         return;
831     }
832 
833     pthread_mutex_lock(&mMutex);
834     if (mGeofenceBreachCallback != nullptr) {
835         size_t count = 0;
836         for (size_t i = 0; i < n; i++) {
837             uint32_t id = mGeofenceBiDict.getId(geofenceBreachNotification.ids[i]);
838             GeofenceBreachTypeMask type =
839                 mGeofenceBiDict.getExtBySession(geofenceBreachNotification.ids[i]);
840             // if type == 0, we will not head into the fllowing block anyway.
841             // so we don't need to check id and type
842             if ((geofenceBreachNotification.type == GEOFENCE_BREACH_ENTER &&
843                         (type & GEOFENCE_BREACH_ENTER_BIT)) ||
844                     (geofenceBreachNotification.type == GEOFENCE_BREACH_EXIT &&
845                      (type & GEOFENCE_BREACH_EXIT_BIT))
846                ) {
847                 ids[count] = id;
848                 count++;
849             }
850         }
851         geofenceBreachNotification.count = count;
852         geofenceBreachNotification.ids = ids;
853 
854         genfenceCallback = mGeofenceBreachCallback;
855     }
856     pthread_mutex_unlock(&mMutex);
857 
858     if (genfenceCallback != nullptr) {
859         genfenceCallback(geofenceBreachNotification);
860     }
861 
862     // restore ids
863     geofenceBreachNotification.ids = backup;
864     geofenceBreachNotification.count = n;
865     free(ids);
866 }
867 
beforeBatchingStatusCb(BatchingStatusInfo batchStatus,std::list<uint32_t> & tripCompletedList)868 void LocationAPIClientBase::beforeBatchingStatusCb(BatchingStatusInfo batchStatus,
869         std::list<uint32_t> & tripCompletedList) {
870 
871     // map the trip ids to the client ids
872     std::list<uint32_t> tripCompletedClientIdList;
873     tripCompletedClientIdList.clear();
874 
875     if (batchStatus.batchingStatus == BATCHING_STATUS_TRIP_COMPLETED) {
876         for (auto itt = tripCompletedList.begin(); itt != tripCompletedList.end(); itt++) {
877             if (mSessionBiDict.hasSession(*itt)) {
878                 SessionEntity sessEntity = mSessionBiDict.getExtBySession(*itt);
879 
880                 if (sessEntity.sessionMode == SESSION_MODE_ON_TRIP_COMPLETED) {
881                     tripCompletedClientIdList.push_back(sessEntity.id);
882                     mSessionBiDict.rmBySession(*itt);
883                 }
884             }
885         }
886     }
887 
888     mBatchingStatusCallback(batchStatus, tripCompletedClientIdList);
889 }
890 
onResponseCb(LocationError error,uint32_t id)891 void LocationAPIClientBase::onResponseCb(LocationError error, uint32_t id)
892 {
893     if (error != LOCATION_ERROR_SUCCESS) {
894         LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, error, id);
895     } else {
896         LOC_LOGV("%s:%d] SUCCESS: %d id: %d", __FUNCTION__, __LINE__, error, id);
897     }
898     LocationAPIRequest* request = getRequestBySession(id);
899     if (request) {
900         request->onResponse(error, id);
901         delete request;
902     }
903 }
904 
onCollectiveResponseCb(size_t count,LocationError * errors,uint32_t * ids)905 void LocationAPIClientBase::onCollectiveResponseCb(
906         size_t count, LocationError* errors, uint32_t* ids)
907 {
908     for (size_t i = 0; i < count; i++) {
909         if (errors[i] != LOCATION_ERROR_SUCCESS) {
910             LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
911         } else {
912             LOC_LOGV("%s:%d] SUCCESS: %d id: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
913         }
914     }
915     LocationAPIRequest* request = nullptr;
916     pthread_mutex_lock(&mMutex);
917     if (mRequestQueues[REQUEST_GEOFENCE].getSession() == GEOFENCE_SESSION_ID) {
918         request = mRequestQueues[REQUEST_GEOFENCE].pop();
919     }
920     pthread_mutex_unlock(&mMutex);
921     if (request) {
922         request->onCollectiveResponse(count, errors, ids);
923         delete request;
924     }
925 }
926 
removeSession(uint32_t session)927 void LocationAPIClientBase::removeSession(uint32_t session) {
928     if (mSessionBiDict.hasSession(session)) {
929         mSessionBiDict.rmBySession(session);
930     }
931 }
932 
getRequestBySession(uint32_t session)933 LocationAPIRequest* LocationAPIClientBase::getRequestBySession(uint32_t session)
934 {
935     pthread_mutex_lock(&mMutex);
936     LocationAPIRequest* request = nullptr;
937     for (int i = 0; i < REQUEST_MAX; i++) {
938         if (i != REQUEST_GEOFENCE &&
939                 i != REQUEST_SESSION &&
940                 mRequestQueues[i].getSession() == session) {
941             request = mRequestQueues[i].pop();
942             break;
943         }
944     }
945     if (request == nullptr) {
946         // Can't find a request with correct session,
947         // try to find it from mSessionBiDict
948         if (mSessionBiDict.hasSession(session)) {
949             request = mRequestQueues[REQUEST_SESSION].pop();
950         }
951     }
952     pthread_mutex_unlock(&mMutex);
953     return request;
954 }
955