blob: 58a8c1746fdb9b520f35190448475d95774fcbe5 [file] [log] [blame]
Michael Bestas3a0209e2023-05-04 01:15:47 +03001/* 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
Michael Bestas222c86c2024-07-18 12:36:55 -040029/* ​​​​​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
Michael Bestas3a0209e2023-05-04 01:15:47 +030034#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
47LocationAPIControlClient::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
73LocationAPIControlClient::~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
91uint32_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
108uint32_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
130void 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
147uint32_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
174uint32_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
196void 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
210void 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
227LocationAPIRequest* 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
242LocationAPIRequest*
243LocationAPIControlClient::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
260LocationAPIClientBase::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
279void 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
320void 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
348LocationAPIClientBase::~LocationAPIClientBase()
349{
350 pthread_mutex_destroy(&mMutex);
351}
352
353void LocationAPIClientBase::onLocationApiDestroyCompleteCb()
354{
355 LOC_LOGD("LocationAPIClientBase::onLocationApiDestroyCompleteCb()");
356 delete this;
357}
358
359uint32_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) {
Michael Bestas222c86c2024-07-18 12:36:55 -0400365 pthread_mutex_unlock(&mMutex);
366 locAPIUpdateTrackingOptions(options);
Michael Bestas3a0209e2023-05-04 01:15:47 +0300367 } 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;
Michael Bestas222c86c2024-07-18 12:36:55 -0400376 pthread_mutex_unlock(&mMutex);
Michael Bestas3a0209e2023-05-04 01:15:47 +0300377 }
378
379 retVal = LOCATION_ERROR_SUCCESS;
Michael Bestas222c86c2024-07-18 12:36:55 -0400380 } else {
381 pthread_mutex_unlock(&mMutex);
Michael Bestas3a0209e2023-05-04 01:15:47 +0300382 }
Michael Bestas3a0209e2023-05-04 01:15:47 +0300383
384 return retVal;
385}
386
387void 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
404void 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
420int32_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
436uint32_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
500uint32_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
532uint32_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
626uint32_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
653uint32_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
678void 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
720void 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
756void 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
790void 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
828void 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
836void 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
849void 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
899void 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
922void 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
936void 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
958void LocationAPIClientBase::removeSession(uint32_t session) {
959 if (mSessionBiDict.hasSession(session)) {
960 mSessionBiDict.rmBySession(session);
961 }
962}
963
964LocationAPIRequest* 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}