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