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