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