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