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_NDDEBUG 0
30#define LOG_TAG "LocSvc_APIClientBase"
31
32#include <log_util.h>
33#include <loc_cfg.h>
34#include "LocationAPIClientBase.h"
35
36#define FLP_CONF_FILE "/vendor/etc/flp.conf"
37#define GEOFENCE_SESSION_ID -1
38
39LocationAPIClientBase::LocationAPIClientBase() :
40    mTrackingCallback(nullptr),
41    mBatchingCallback(nullptr),
42    mGeofenceBreachCallback(nullptr),
43    mLocationAPI(nullptr),
44    mLocationControlAPI(nullptr),
45    mBatchSize(-1),
46    mEnabled(false),
47    mTracking(false)
48{
49
50    // use recursive mutex, in case callback come from the same thread
51    pthread_mutexattr_t attr;
52    pthread_mutexattr_init(&attr);
53    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
54    pthread_mutex_init(&mMutex, &attr);
55
56    for (int i = 0; i < REQUEST_MAX; i++) {
57        mRequestQueues[i] = nullptr;
58    }
59
60    memset(&mConfig, 0, sizeof(GnssConfig));
61}
62
63void LocationAPIClientBase::locAPISetCallbacks(LocationCallbacks& locationCallbacks)
64{
65    pthread_mutex_lock(&mMutex);
66
67    if (locationCallbacks.geofenceBreachCb != nullptr) {
68        mGeofenceBreachCallback = locationCallbacks.geofenceBreachCb;
69        locationCallbacks.geofenceBreachCb =
70            [this](GeofenceBreachNotification geofenceBreachNotification) {
71                beforeGeofenceBreachCb(geofenceBreachNotification);
72            };
73    }
74
75    locationCallbacks.capabilitiesCb =
76        [this](LocationCapabilitiesMask capabilitiesMask) {
77            onCapabilitiesCb(capabilitiesMask);
78        };
79    locationCallbacks.responseCb = [this](LocationError error, uint32_t id) {
80        onResponseCb(error, id);
81    };
82    locationCallbacks.collectiveResponseCb =
83        [this](size_t count, LocationError* errors, uint32_t* ids) {
84            onCollectiveResponseCb(count, errors, ids);
85        };
86
87    if (mLocationAPI == nullptr ) {
88        mLocationAPI = LocationAPI::createInstance(locationCallbacks);
89    } else {
90        mLocationAPI->updateCallbacks(locationCallbacks);
91    }
92
93    if (mLocationControlAPI == nullptr) {
94        LocationControlCallbacks locationControlCallbacks;
95        locationControlCallbacks.size = sizeof(LocationControlCallbacks);
96
97        locationControlCallbacks.responseCb =
98            [this](LocationError error, uint32_t id) {
99                onCtrlResponseCb(error, id);
100            };
101        locationControlCallbacks.collectiveResponseCb =
102            [this](size_t count, LocationError* errors, uint32_t* ids) {
103                onCtrlCollectiveResponseCb(count, errors, ids);
104            };
105
106        mLocationControlAPI = LocationControlAPI::createInstance(locationControlCallbacks);
107    }
108
109    pthread_mutex_unlock(&mMutex);
110}
111
112LocationAPIClientBase::~LocationAPIClientBase()
113{
114    pthread_mutex_lock(&mMutex);
115
116    if (mLocationAPI) {
117        mLocationAPI->destroy();
118        mLocationAPI = nullptr;
119    }
120    if (mLocationControlAPI) {
121        mLocationControlAPI->destroy();
122        mLocationControlAPI = nullptr;
123    }
124
125    for (int i = 0; i < REQUEST_MAX; i++) {
126        if (mRequestQueues[i]) {
127            delete mRequestQueues[i];
128            mRequestQueues[i] = nullptr;
129        }
130    }
131    pthread_mutex_unlock(&mMutex);
132
133    pthread_mutex_destroy(&mMutex);
134}
135
136uint32_t LocationAPIClientBase::locAPIStartTracking(LocationOptions& options)
137{
138    uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
139    pthread_mutex_lock(&mMutex);
140    if (mLocationAPI) {
141        if (mTracking) {
142            LOC_LOGW("%s:%d] Existing tracking session present", __FUNCTION__, __LINE__);
143        } else {
144            RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
145            if (requests) {
146                delete requests;
147                mRequestQueues[REQUEST_TRACKING] = nullptr;
148            }
149            uint32_t session = mLocationAPI->startTracking(options);
150            LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
151            // onResponseCb might be called from other thread immediately after
152            // startTracking returns, so we are not going to unlock mutex
153            // until StartTrackingRequest is pushed into mRequestQueues[REQUEST_TRACKING]
154            requests = new RequestQueue(session);
155            requests->push(new StartTrackingRequest(*this));
156            mRequestQueues[REQUEST_TRACKING] = requests;
157            mTracking = true;
158        }
159        retVal = LOCATION_ERROR_SUCCESS;
160    }
161    pthread_mutex_unlock(&mMutex);
162
163    return retVal;
164}
165
166void LocationAPIClientBase::locAPIStopTracking()
167{
168    pthread_mutex_lock(&mMutex);
169    if (mLocationAPI) {
170        uint32_t session = 0;
171        RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
172        if (requests) {
173            session = requests->getSession();
174            if (session > 0) {
175                requests->push(new StopTrackingRequest(*this));
176                mLocationAPI->stopTracking(session);
177                mTracking = false;
178            }
179        }
180    }
181    pthread_mutex_unlock(&mMutex);
182}
183
184void LocationAPIClientBase::locAPIUpdateTrackingOptions(LocationOptions& options)
185{
186    pthread_mutex_lock(&mMutex);
187    if (mLocationAPI) {
188        uint32_t session = 0;
189        RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
190        if (requests) {
191            session = requests->getSession();
192            if (session > 0) {
193                requests->push(new UpdateTrackingOptionsRequest(*this));
194                mLocationAPI->updateTrackingOptions(session, options);
195            }
196        }
197    }
198    pthread_mutex_unlock(&mMutex);
199}
200
201int32_t LocationAPIClientBase::locAPIGetBatchSize()
202{
203    if (mBatchSize == -1) {
204        const loc_param_s_type flp_conf_param_table[] =
205        {
206            {"BATCH_SIZE", &mBatchSize, nullptr, 'n'},
207        };
208        UTIL_READ_CONF(FLP_CONF_FILE, flp_conf_param_table);
209        if (mBatchSize < 0) {
210            // set mBatchSize to 0 if we got an illegal value from config file
211            mBatchSize = 0;
212        }
213    }
214    return mBatchSize;
215}
216
217
218uint32_t LocationAPIClientBase::locAPIStartSession(uint32_t id, uint32_t sessionMode,
219        LocationOptions& options)
220{
221    uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
222    pthread_mutex_lock(&mMutex);
223    if (mLocationAPI) {
224
225        if (mSessionMap.find(id) != mSessionMap.end()) {
226            LOC_LOGE("%s:%d] session %d has already started.", __FUNCTION__, __LINE__, id);
227            retVal = LOCATION_ERROR_ALREADY_STARTED;
228        } else {
229            uint32_t trackingSession = 0;
230            uint32_t batchingSession = 0;
231
232            if (sessionMode == SESSION_MODE_ON_FIX) {
233                RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
234                if (requests) {
235                    delete requests;
236                    mRequestQueues[REQUEST_TRACKING] = nullptr;
237                }
238                trackingSession = mLocationAPI->startTracking(options);
239                LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, trackingSession);
240                requests = new RequestQueue(trackingSession);
241                requests->push(new StartTrackingRequest(*this));
242                mRequestQueues[REQUEST_TRACKING] = requests;
243            } else if (sessionMode == SESSION_MODE_ON_FULL) {
244                RequestQueue* requests = mRequestQueues[REQUEST_BATCHING];
245                if (requests) {
246                    delete requests;
247                    mRequestQueues[REQUEST_BATCHING] = nullptr;
248                }
249                batchingSession = mLocationAPI->startBatching(options);
250                LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, batchingSession);
251                requests = new RequestQueue(batchingSession);
252                requests->push(new StartBatchingRequest(*this));
253                mRequestQueues[REQUEST_BATCHING] = requests;
254            }
255
256            SessionEntity entity;
257            entity.id = id;
258            entity.trackingSession = trackingSession;
259            entity.batchingSession = batchingSession;
260            entity.sessionMode = sessionMode;
261            mSessionMap[id] = entity;
262
263            retVal = LOCATION_ERROR_SUCCESS;
264        }
265
266    }
267    pthread_mutex_unlock(&mMutex);
268
269    return retVal;
270}
271
272uint32_t LocationAPIClientBase::locAPIStopSession(uint32_t id)
273{
274    uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
275    pthread_mutex_lock(&mMutex);
276    if (mLocationAPI) {
277
278        if (mSessionMap.find(id) != mSessionMap.end()) {
279            SessionEntity entity = mSessionMap[id];
280
281            uint32_t trackingSession = entity.trackingSession;
282            uint32_t batchingSession = entity.batchingSession;
283            uint32_t sMode = entity.sessionMode;
284
285            mSessionMap.erase(id);
286
287            if (sMode == SESSION_MODE_ON_FIX) {
288                RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
289                if (requests) {
290                    requests->push(new StopTrackingRequest(*this));
291                    mLocationAPI->stopTracking(trackingSession);
292                }
293            } else if (sMode == SESSION_MODE_ON_FULL) {
294                RequestQueue* requests = mRequestQueues[REQUEST_BATCHING];
295                if (requests) {
296                    requests->push(new StopBatchingRequest(*this));
297                    mLocationAPI->stopBatching(batchingSession);
298                }
299            }
300
301            retVal = LOCATION_ERROR_SUCCESS;
302        } else {
303            retVal = LOCATION_ERROR_ID_UNKNOWN;
304            LOC_LOGE("%s:%d] session %d is not exist.", __FUNCTION__, __LINE__, id);
305        }
306
307    }
308    pthread_mutex_unlock(&mMutex);
309    return retVal;
310}
311
312uint32_t LocationAPIClientBase::locAPIUpdateSessionOptions(uint32_t id, uint32_t sessionMode,
313        LocationOptions& options)
314{
315    uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
316    pthread_mutex_lock(&mMutex);
317    if (mLocationAPI) {
318
319        if (mSessionMap.find(id) != mSessionMap.end()) {
320            SessionEntity& entity = mSessionMap[id];
321
322            uint32_t trackingSession = entity.trackingSession;
323            uint32_t batchingSession = entity.batchingSession;
324            uint32_t sMode = entity.sessionMode;
325
326            if (sessionMode == SESSION_MODE_ON_FIX) {
327                if (sMode == SESSION_MODE_ON_FIX) {
328                    RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
329                    if (requests) {
330                        requests->push(new UpdateTrackingOptionsRequest(*this));
331                        mLocationAPI->updateTrackingOptions(trackingSession, options);
332                    }
333                } else if (sMode == SESSION_MODE_ON_FULL) {
334                    // stop batching
335                    {
336                        RequestQueue* requests = mRequestQueues[REQUEST_BATCHING];
337                        if (requests) {
338                            requests->push(new StopBatchingRequest(*this));
339                            mLocationAPI->stopBatching(batchingSession);
340                            batchingSession = 0;
341                        }
342                    }
343                    // start tracking
344                    {
345                        RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
346                        if (requests) {
347                            delete requests;
348                            mRequestQueues[REQUEST_TRACKING] = nullptr;
349                        }
350                        trackingSession = mLocationAPI->startTracking(options);
351                        LOC_LOGI("%s:%d] start new session: %d",
352                                __FUNCTION__, __LINE__, trackingSession);
353                        requests = new RequestQueue(trackingSession);
354                        requests->push(new StartTrackingRequest(*this));
355                        mRequestQueues[REQUEST_TRACKING] = requests;
356                    }
357                }
358            } else if (sessionMode == SESSION_MODE_ON_FULL) {
359                if (sMode == SESSION_MODE_ON_FIX) {
360                    // stop tracking
361                    {
362                        RequestQueue* requests = mRequestQueues[REQUEST_TRACKING];
363                        if (requests) {
364                            requests->push(new StopTrackingRequest(*this));
365                            mLocationAPI->stopTracking(trackingSession);
366                            trackingSession = 0;
367                        }
368                    }
369                    // start batching
370                    {
371                        RequestQueue* requests = mRequestQueues[REQUEST_BATCHING];
372                        if (requests) {
373                            delete requests;
374                            mRequestQueues[REQUEST_BATCHING] = nullptr;
375                        }
376                        batchingSession = mLocationAPI->startBatching(options);
377                        LOC_LOGI("%s:%d] start new session: %d",
378                                __FUNCTION__, __LINE__, batchingSession);
379                        requests = new RequestQueue(batchingSession);
380                        requests->push(new StartBatchingRequest(*this));
381                        mRequestQueues[REQUEST_BATCHING] = requests;
382                    }
383                } else if (sMode == SESSION_MODE_ON_FULL) {
384                    RequestQueue* requests = mRequestQueues[REQUEST_BATCHING];
385                    requests = mRequestQueues[REQUEST_BATCHING];
386                    if (requests) {
387                        requests->push(new UpdateBatchingOptionsRequest(*this));
388                        mLocationAPI->updateBatchingOptions(batchingSession, options);
389                    }
390                }
391            }
392
393            entity.trackingSession = trackingSession;
394            entity.batchingSession = batchingSession;
395            entity.sessionMode = sessionMode;
396
397            retVal = LOCATION_ERROR_SUCCESS;
398        } else {
399            retVal = LOCATION_ERROR_ID_UNKNOWN;
400            LOC_LOGE("%s:%d] session %d is not exist.", __FUNCTION__, __LINE__, id);
401        }
402
403    }
404    pthread_mutex_unlock(&mMutex);
405    return retVal;
406}
407
408void LocationAPIClientBase::locAPIGetBatchedLocations(size_t count)
409{
410    pthread_mutex_lock(&mMutex);
411    if (mLocationAPI) {
412        uint32_t session = 0;
413        RequestQueue* requests = mRequestQueues[REQUEST_BATCHING];
414        if (requests) {
415            session = requests->getSession();
416            if (session > 0) {
417                requests->push(new GetBatchedLocationsRequest(*this));
418                mLocationAPI->getBatchedLocations(session, count);
419            }
420        }
421    }
422    pthread_mutex_unlock(&mMutex);
423}
424
425uint32_t LocationAPIClientBase::locAPIAddGeofences(
426        size_t count, uint32_t* ids, GeofenceOption* options, GeofenceInfo* data)
427{
428    uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
429    pthread_mutex_lock(&mMutex);
430    if (mLocationAPI) {
431        RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE];
432        if (!requests) {
433            // Create a new RequestQueue for Geofenceing if we've not had one.
434            // The RequestQueue will be released when LocationAPIClientBase is released.
435            requests = new RequestQueue(GEOFENCE_SESSION_ID);
436            mRequestQueues[REQUEST_GEOFENCE] = requests;
437        }
438        uint32_t* sessions = mLocationAPI->addGeofences(count, options, data);
439        if (sessions) {
440            LOC_LOGI("%s:%d] start new sessions: %p", __FUNCTION__, __LINE__, sessions);
441            requests->push(new AddGeofencesRequest(*this));
442
443            for (size_t i = 0; i < count; i++) {
444                mGeofenceBiDict.set(ids[i], sessions[i], options[i].breachTypeMask);
445            }
446            retVal = LOCATION_ERROR_SUCCESS;
447        }
448    }
449    pthread_mutex_unlock(&mMutex);
450
451    return retVal;
452}
453
454void LocationAPIClientBase::locAPIRemoveGeofences(size_t count, uint32_t* ids)
455{
456    pthread_mutex_lock(&mMutex);
457    if (mLocationAPI) {
458        uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
459
460        RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE];
461        if (requests) {
462            size_t j = 0;
463            for (size_t i = 0; i < count; i++) {
464                sessions[j] = mGeofenceBiDict.getSession(ids[i]);
465                if (sessions[j] > 0) {
466                    j++;
467                }
468            }
469            if (j > 0) {
470                requests->push(new RemoveGeofencesRequest(*this));
471                mLocationAPI->removeGeofences(j, sessions);
472            }
473        }
474
475        free(sessions);
476    }
477    pthread_mutex_unlock(&mMutex);
478}
479
480void LocationAPIClientBase::locAPIModifyGeofences(
481        size_t count, uint32_t* ids, GeofenceOption* options)
482{
483    pthread_mutex_lock(&mMutex);
484    if (mLocationAPI) {
485        uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
486
487        RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE];
488        if (requests) {
489            size_t j = 0;
490            for (size_t i = 0; i < count; i++) {
491                sessions[j] = mGeofenceBiDict.getSession(ids[i]);
492                if (sessions[j] > 0) {
493                    mGeofenceBiDict.set(ids[i], sessions[j], options[i].breachTypeMask);
494                    j++;
495                }
496            }
497            if (j > 0) {
498                requests->push(new ModifyGeofencesRequest(*this));
499                mLocationAPI->modifyGeofences(j, sessions, options);
500            }
501        }
502
503        free(sessions);
504    }
505    pthread_mutex_unlock(&mMutex);
506}
507
508void LocationAPIClientBase::locAPIPauseGeofences(size_t count, uint32_t* ids)
509{
510    pthread_mutex_lock(&mMutex);
511    if (mLocationAPI) {
512        uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
513
514        RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE];
515        if (requests) {
516            size_t j = 0;
517            for (size_t i = 0; i < count; i++) {
518                sessions[j] = mGeofenceBiDict.getSession(ids[i]);
519                if (sessions[j] > 0) {
520                    j++;
521                }
522            }
523            if (j > 0) {
524                requests->push(new PauseGeofencesRequest(*this));
525                mLocationAPI->pauseGeofences(j, sessions);
526            }
527        }
528
529        free(sessions);
530    }
531    pthread_mutex_unlock(&mMutex);
532}
533
534void LocationAPIClientBase::locAPIResumeGeofences(
535        size_t count, uint32_t* ids, GeofenceBreachTypeMask* mask)
536{
537    pthread_mutex_lock(&mMutex);
538    if (mLocationAPI) {
539        uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
540
541        RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE];
542        if (requests) {
543            size_t j = 0;
544            for (size_t i = 0; i < count; i++) {
545                sessions[j] = mGeofenceBiDict.getSession(ids[i]);
546                if (sessions[j] > 0) {
547                    if (mask) {
548                        mGeofenceBiDict.set(ids[i], sessions[j], mask[i]);
549                    }
550                    j++;
551                }
552            }
553            if (j > 0) {
554                requests->push(new ResumeGeofencesRequest(*this));
555                mLocationAPI->resumeGeofences(j, sessions);
556            }
557        }
558
559        free(sessions);
560    }
561    pthread_mutex_unlock(&mMutex);
562}
563
564void LocationAPIClientBase::locAPIRemoveAllGeofences()
565{
566    pthread_mutex_lock(&mMutex);
567    if (mLocationAPI) {
568        std::vector<uint32_t> sessionsVec = mGeofenceBiDict.getAllSessions();
569        size_t count = sessionsVec.size();
570        uint32_t* sessions = (uint32_t*)malloc(sizeof(uint32_t) * count);
571
572        RequestQueue* requests = mRequestQueues[REQUEST_GEOFENCE];
573        if (requests) {
574            size_t j = 0;
575            for (size_t i = 0; i < count; i++) {
576                sessions[j] = sessionsVec[i];
577                if (sessions[j] > 0) {
578                    j++;
579                }
580            }
581            if (j > 0) {
582                requests->push(new RemoveGeofencesRequest(*this));
583                mLocationAPI->removeGeofences(j, sessions);
584            }
585        }
586
587        free(sessions);
588    }
589    pthread_mutex_unlock(&mMutex);
590}
591
592void LocationAPIClientBase::locAPIGnssNiResponse(uint32_t id, GnssNiResponse response)
593{
594    pthread_mutex_lock(&mMutex);
595    if (mLocationAPI) {
596        RequestQueue* requests = mRequestQueues[REQUEST_NIRESPONSE];
597        if (requests) {
598            delete requests;
599            mRequestQueues[REQUEST_NIRESPONSE] = nullptr;
600        }
601        uint32_t session = id;
602        mLocationAPI->gnssNiResponse(id, response);
603        LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
604        requests = new RequestQueue(session);
605        requests->push(new GnssNiResponseRequest(*this));
606        mRequestQueues[REQUEST_NIRESPONSE] = requests;
607    }
608    pthread_mutex_unlock(&mMutex);
609}
610
611uint32_t LocationAPIClientBase::locAPIGnssDeleteAidingData(GnssAidingData& data)
612{
613    uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
614    pthread_mutex_lock(&mMutex);
615    if (mLocationControlAPI) {
616        RequestQueue* requests = mRequestQueues[REQUEST_DELETEAIDINGDATA];
617        if (requests) {
618            delete requests;
619            mRequestQueues[REQUEST_DELETEAIDINGDATA] = nullptr;
620        }
621        uint32_t session = mLocationControlAPI->gnssDeleteAidingData(data);
622        LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
623        requests = new RequestQueue(session);
624        requests->push(new GnssDeleteAidingDataRequest(*this));
625        mRequestQueues[REQUEST_DELETEAIDINGDATA] = requests;
626
627        retVal = LOCATION_ERROR_SUCCESS;
628    }
629    pthread_mutex_unlock(&mMutex);
630
631    return retVal;
632}
633
634uint32_t LocationAPIClientBase::locAPIEnable(LocationTechnologyType techType)
635{
636    uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
637    pthread_mutex_lock(&mMutex);
638    if (mEnabled) {
639        // just return success if already enabled
640        retVal = LOCATION_ERROR_SUCCESS;
641    } else if (mLocationControlAPI) {
642        RequestQueue* requests = mRequestQueues[REQUEST_CONTROL];
643        if (requests) {
644            delete requests;
645            mRequestQueues[REQUEST_CONTROL] = nullptr;
646        }
647        uint32_t session = mLocationControlAPI->enable(techType);
648        LOC_LOGI("%s:%d] start new session: %d", __FUNCTION__, __LINE__, session);
649        requests = new RequestQueue(session);
650        mRequestQueues[REQUEST_CONTROL] = requests;
651        if (requests) {
652            requests->push(new EnableRequest(*this));
653            retVal = LOCATION_ERROR_SUCCESS;
654            mEnabled = true;
655        }
656    }
657    pthread_mutex_unlock(&mMutex);
658
659    return retVal;
660}
661
662void LocationAPIClientBase::locAPIDisable()
663{
664    pthread_mutex_lock(&mMutex);
665    if (mEnabled && mLocationControlAPI) {
666        uint32_t session = 0;
667        RequestQueue* requests = mRequestQueues[REQUEST_CONTROL];
668        if (requests) {
669            session = requests->getSession();
670            if (session > 0) {
671                requests->push(new DisableRequest(*this));
672                mLocationControlAPI->disable(session);
673                mEnabled = false;
674            }
675        }
676    }
677    pthread_mutex_unlock(&mMutex);
678}
679
680uint32_t LocationAPIClientBase::locAPIGnssUpdateConfig(GnssConfig config)
681{
682    uint32_t retVal = LOCATION_ERROR_GENERAL_FAILURE;
683    if (memcmp(&mConfig, &config, sizeof(GnssConfig)) == 0) {
684        LOC_LOGV("%s:%d] GnssConfig is identical to previous call", __FUNCTION__, __LINE__);
685        retVal = LOCATION_ERROR_SUCCESS;
686        return retVal;
687    }
688
689    pthread_mutex_lock(&mMutex);
690    if (mLocationControlAPI) {
691
692        memcpy(&mConfig, &config, sizeof(GnssConfig));
693
694        uint32_t session = 0;
695        RequestQueue* requests = mRequestQueues[REQUEST_CONFIG];
696        uint32_t* idArray = mLocationControlAPI->gnssUpdateConfig(config);
697        LOC_LOGV("%s:%d] gnssUpdateConfig return array: %p", __FUNCTION__, __LINE__, idArray);
698        if (!requests && idArray != nullptr) {
699            requests = new RequestQueue(idArray[0]);
700            mRequestQueues[REQUEST_CONFIG] = requests;
701        }
702        if (requests) {
703            requests->push(new GnssUpdateConfigRequest(*this));
704            retVal = LOCATION_ERROR_SUCCESS;
705        }
706    }
707    pthread_mutex_unlock(&mMutex);
708    return retVal;
709}
710
711void LocationAPIClientBase::beforeGeofenceBreachCb(
712        GeofenceBreachNotification geofenceBreachNotification)
713{
714    if (mGeofenceBreachCallback == nullptr)
715        return;
716    uint32_t* ids = (uint32_t*)malloc(sizeof(uint32_t) * geofenceBreachNotification.count);
717    uint32_t* backup = geofenceBreachNotification.ids;
718    size_t n = geofenceBreachNotification.count;
719
720    size_t count = 0;
721    for (size_t i = 0; i < n; i++) {
722        uint32_t id = mGeofenceBiDict.getId(geofenceBreachNotification.ids[i]);
723        GeofenceBreachTypeMask type = mGeofenceBiDict.getType(geofenceBreachNotification.ids[i]);
724        // if type == 0, we will not head into the fllowing block anyway.
725        // so we don't need to check id and type
726        if ((geofenceBreachNotification.type == GEOFENCE_BREACH_ENTER &&
727            (type & GEOFENCE_BREACH_ENTER_BIT)) ||
728            (geofenceBreachNotification.type == GEOFENCE_BREACH_EXIT &&
729            (type & GEOFENCE_BREACH_EXIT_BIT))
730           ) {
731            ids[count] = id;
732            count++;
733        }
734    }
735    geofenceBreachNotification.count = count;
736    geofenceBreachNotification.ids = ids;
737    mGeofenceBreachCallback(geofenceBreachNotification);
738
739    // restore ids
740    geofenceBreachNotification.ids = backup;
741    geofenceBreachNotification.count = n;
742    free(ids);
743}
744
745void LocationAPIClientBase::onResponseCb(LocationError error, uint32_t id)
746{
747    if (error != LOCATION_ERROR_SUCCESS) {
748        LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, error, id);
749    } else {
750        LOC_LOGV("%s:%d] error: %d id: %d", __FUNCTION__, __LINE__, error, id);
751    }
752    LocationAPIRequest* request = getRequestBySession(id);
753    if (request) {
754        request->onResponse(error);
755        delete request;
756    }
757}
758
759void LocationAPIClientBase::onCollectiveResponseCb(
760        size_t count, LocationError* errors, uint32_t* ids)
761{
762    for (size_t i = 0; i < count; i++) {
763        if (errors[i] != LOCATION_ERROR_SUCCESS) {
764            LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
765        } else {
766            LOC_LOGV("%s:%d] error: %d id: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
767        }
768    }
769    LocationAPIRequest* request = nullptr;
770    pthread_mutex_lock(&mMutex);
771    if (mRequestQueues[REQUEST_GEOFENCE] != nullptr) {
772        request = mRequestQueues[REQUEST_GEOFENCE]->pop();
773    }
774    pthread_mutex_unlock(&mMutex);
775    if (request) {
776        request->onCollectiveResponse(count, errors, ids);
777        delete request;
778    }
779}
780
781void LocationAPIClientBase::onCtrlResponseCb(LocationError error, uint32_t id)
782{
783    if (error != LOCATION_ERROR_SUCCESS) {
784        LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, error, id);
785    } else {
786        LOC_LOGV("%s:%d] error: %d id: %d", __FUNCTION__, __LINE__, error, id);
787    }
788    LocationAPIRequest* request = getRequestBySession(id);
789    if (request) {
790        request->onResponse(error);
791        delete request;
792    }
793}
794
795void LocationAPIClientBase::onCtrlCollectiveResponseCb(
796        size_t count, LocationError* errors, uint32_t* ids)
797{
798    for (size_t i = 0; i < count; i++) {
799        if (errors[i] != LOCATION_ERROR_SUCCESS) {
800            LOC_LOGE("%s:%d] ERROR: %d ID: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
801        } else {
802            LOC_LOGV("%s:%d] error: %d id: %d", __FUNCTION__, __LINE__, errors[i], ids[i]);
803        }
804    }
805    LocationAPIRequest* request = nullptr;
806    pthread_mutex_lock(&mMutex);
807    if (mRequestQueues[REQUEST_CONFIG] != nullptr) {
808        request = mRequestQueues[REQUEST_CONFIG]->pop();
809    }
810    pthread_mutex_unlock(&mMutex);
811    if (request) {
812        request->onCollectiveResponse(count, errors, ids);
813        delete request;
814    }
815}
816
817LocationAPIClientBase::LocationAPIRequest*
818LocationAPIClientBase::getRequestBySession(uint32_t session)
819{
820    pthread_mutex_lock(&mMutex);
821    LocationAPIRequest* request = nullptr;
822    for (int i = 0; i < REQUEST_MAX; i++) {
823        if (i != REQUEST_GEOFENCE &&
824                i != REQUEST_CONFIG &&
825                mRequestQueues[i] &&
826                mRequestQueues[i]->getSession() == session) {
827            request = mRequestQueues[i]->pop();
828            break;
829        }
830    }
831    pthread_mutex_unlock(&mMutex);
832    return request;
833}
834