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#define LOG_TAG "LocSvc_LocationAPI"
29
30#include <location_interface.h>
31#include <dlfcn.h>
32#include <log_util.h>
33#include <pthread.h>
34#include <map>
35
36typedef void* (getLocationInterface)();
37typedef std::map<LocationAPI*, LocationCallbacks> LocationClientMap;
38typedef struct {
39    LocationClientMap clientData;
40    LocationControlAPI* controlAPI;
41    LocationControlCallbacks controlCallbacks;
42    GnssInterface* gnssInterface;
43    GeofenceInterface* geofenceInterface;
44    FlpInterface* flpInterface;
45} LocationAPIData;
46static LocationAPIData gData = {};
47static pthread_mutex_t gDataMutex = PTHREAD_MUTEX_INITIALIZER;
48static bool gGnssLoadFailed = false;
49static bool gFlpLoadFailed = false;
50static bool gGeofenceLoadFailed = false;
51
52static bool needsGnssTrackingInfo(LocationCallbacks& locationCallbacks)
53{
54    return (locationCallbacks.gnssLocationInfoCb != nullptr ||
55            locationCallbacks.gnssSvCb != nullptr ||
56            locationCallbacks.gnssNmeaCb != nullptr ||
57            locationCallbacks.gnssMeasurementsCb != nullptr);
58}
59
60static bool isGnssClient(LocationCallbacks& locationCallbacks)
61{
62    return (locationCallbacks.gnssNiCb != nullptr ||
63            locationCallbacks.trackingCb != nullptr ||
64            locationCallbacks.gnssMeasurementsCb != nullptr);
65}
66
67static bool isFlpClient(LocationCallbacks& locationCallbacks)
68{
69    return (locationCallbacks.trackingCb != nullptr ||
70            locationCallbacks.batchingCb != nullptr);
71}
72
73static bool isGeofenceClient(LocationCallbacks& locationCallbacks)
74{
75    return (locationCallbacks.geofenceBreachCb != nullptr ||
76            locationCallbacks.geofenceStatusCb != nullptr);
77}
78
79static void* loadLocationInterface(const char* library, const char* name) {
80    LOC_LOGD("%s]: loading %s::%s ...", __func__, library, name);
81    if (NULL == library || NULL == name) {
82        return NULL;
83    }
84    getLocationInterface* getter = NULL;
85    const char *error = NULL;
86    dlerror();
87    void *handle = dlopen(library, RTLD_NOW);
88    if (NULL == handle || (error = dlerror()) != NULL)  {
89        LOC_LOGW("dlopen for %s failed, error = %s", library, error);
90    } else {
91        getter = (getLocationInterface*)dlsym(handle, name);
92        if ((error = dlerror()) != NULL)  {
93            LOC_LOGW("dlsym for %s::%s failed, error = %s", library, name, error);
94            getter = NULL;
95        }
96    }
97
98    if (NULL == getter) {
99        return (void*)getter;
100    } else {
101        return (*getter)();
102    }
103}
104
105LocationAPI*
106LocationAPI::createInstance(LocationCallbacks& locationCallbacks)
107{
108    if (nullptr == locationCallbacks.capabilitiesCb ||
109        nullptr == locationCallbacks.responseCb ||
110        nullptr == locationCallbacks.collectiveResponseCb) {
111        return NULL;
112    }
113
114    LocationAPI* newLocationAPI = new LocationAPI();
115    bool requestedCapabilities = false;
116
117    pthread_mutex_lock(&gDataMutex);
118
119    if (isGnssClient(locationCallbacks)) {
120        if (NULL == gData.gnssInterface && !gGnssLoadFailed) {
121            gData.gnssInterface =
122                (GnssInterface*)loadLocationInterface("libgnss.so", "getGnssInterface");
123            if (NULL == gData.gnssInterface) {
124                gGnssLoadFailed = true;
125                LOC_LOGW("%s:%d]: No gnss interface available", __func__, __LINE__);
126            } else {
127                gData.gnssInterface->initialize();
128            }
129        }
130        if (NULL != gData.gnssInterface) {
131            gData.gnssInterface->addClient(newLocationAPI, locationCallbacks);
132            if (!requestedCapabilities) {
133                gData.gnssInterface->requestCapabilities(newLocationAPI);
134                requestedCapabilities = true;
135            }
136        }
137    }
138
139    if (isFlpClient(locationCallbacks)) {
140        if (NULL == gData.flpInterface && !gFlpLoadFailed) {
141            gData.flpInterface =
142                (FlpInterface*)loadLocationInterface("libflp.so", "getFlpInterface");
143            if (NULL == gData.flpInterface) {
144                gFlpLoadFailed = true;
145                LOC_LOGW("%s:%d]: No flp interface available", __func__, __LINE__);
146            } else {
147                gData.flpInterface->initialize();
148            }
149        }
150        if (NULL != gData.flpInterface) {
151            gData.flpInterface->addClient(newLocationAPI, locationCallbacks);
152            if (!requestedCapabilities) {
153                gData.flpInterface->requestCapabilities(newLocationAPI);
154                requestedCapabilities = true;
155            }
156        }
157    }
158
159    if (isGeofenceClient(locationCallbacks)) {
160        if (NULL == gData.geofenceInterface && !gGeofenceLoadFailed) {
161            gData.geofenceInterface =
162                (GeofenceInterface*)loadLocationInterface("libgeofence.so", "getGeofenceInterface");
163            if (NULL == gData.geofenceInterface) {
164                gGeofenceLoadFailed = true;
165                LOC_LOGW("%s:%d]: No geofence interface available", __func__, __LINE__);
166            } else {
167                gData.geofenceInterface->initialize();
168            }
169        }
170        if (NULL != gData.geofenceInterface) {
171            gData.geofenceInterface->addClient(newLocationAPI, locationCallbacks);
172            if (!requestedCapabilities) {
173                gData.geofenceInterface->requestCapabilities(newLocationAPI);
174                requestedCapabilities = true;
175            }
176        }
177    }
178
179    gData.clientData[newLocationAPI] = locationCallbacks;
180
181    pthread_mutex_unlock(&gDataMutex);
182
183    return newLocationAPI;
184}
185
186void
187LocationAPI::destroy()
188{
189    delete this;
190}
191
192LocationAPI::LocationAPI()
193{
194    LOC_LOGD("LOCATION API CONSTRUCTOR");
195}
196
197LocationAPI::~LocationAPI()
198{
199    LOC_LOGD("LOCATION API DESTRUCTOR");
200    pthread_mutex_lock(&gDataMutex);
201
202    auto it = gData.clientData.find(this);
203    if (it != gData.clientData.end()) {
204        if (isGnssClient(it->second) && NULL != gData.gnssInterface) {
205            gData.gnssInterface->removeClient(it->first);
206        }
207        if (isFlpClient(it->second) && NULL != gData.flpInterface) {
208            gData.flpInterface->removeClient(it->first);
209        }
210        if (isGeofenceClient(it->second) && NULL != gData.geofenceInterface) {
211            gData.geofenceInterface->removeClient(it->first);
212        }
213        gData.clientData.erase(it);
214    } else {
215        LOC_LOGE("%s:%d]: Location API client %p not found in client data",
216                 __func__, __LINE__, this);
217    }
218
219    pthread_mutex_unlock(&gDataMutex);
220}
221
222void
223LocationAPI::updateCallbacks(LocationCallbacks& locationCallbacks)
224{
225    if (nullptr == locationCallbacks.capabilitiesCb ||
226        nullptr == locationCallbacks.responseCb ||
227        nullptr == locationCallbacks.collectiveResponseCb) {
228        return;
229    }
230
231    pthread_mutex_lock(&gDataMutex);
232
233    if (isGnssClient(locationCallbacks)) {
234        if (NULL == gData.gnssInterface && !gGnssLoadFailed) {
235            gData.gnssInterface =
236                (GnssInterface*)loadLocationInterface("libgnss.so", "getGnssInterface");
237            if (NULL == gData.gnssInterface) {
238                gGnssLoadFailed = true;
239                LOC_LOGW("%s:%d]: No gnss interface available", __func__, __LINE__);
240            } else {
241                gData.gnssInterface->initialize();
242            }
243        }
244        if (NULL != gData.gnssInterface) {
245            // either adds new Client or updates existing Client
246            gData.gnssInterface->addClient(this, locationCallbacks);
247        }
248    }
249
250    if (isFlpClient(locationCallbacks)) {
251        if (NULL == gData.flpInterface && !gFlpLoadFailed) {
252            gData.flpInterface =
253                (FlpInterface*)loadLocationInterface("libflp.so", "getFlpInterface");
254            if (NULL == gData.flpInterface) {
255                gFlpLoadFailed = true;
256                LOC_LOGW("%s:%d]: No flp interface available", __func__, __LINE__);
257            } else {
258                gData.flpInterface->initialize();
259            }
260        }
261        if (NULL != gData.flpInterface) {
262            // either adds new Client or updates existing Client
263            gData.flpInterface->addClient(this, locationCallbacks);
264        }
265    }
266
267    if (isGeofenceClient(locationCallbacks)) {
268        if (NULL == gData.geofenceInterface && !gGeofenceLoadFailed) {
269            gData.geofenceInterface =
270                (GeofenceInterface*)loadLocationInterface("libgeofence.so", "getGeofenceInterface");
271            if (NULL == gData.geofenceInterface) {
272                gGeofenceLoadFailed = true;
273                LOC_LOGW("%s:%d]: No geofence interface available", __func__, __LINE__);
274            } else {
275                gData.geofenceInterface->initialize();
276            }
277        }
278        if (NULL != gData.geofenceInterface) {
279            // either adds new Client or updates existing Client
280            gData.geofenceInterface->addClient(this, locationCallbacks);
281        }
282    }
283
284    gData.clientData[this] = locationCallbacks;
285
286    pthread_mutex_unlock(&gDataMutex);
287}
288
289uint32_t
290LocationAPI::startTracking(LocationOptions& locationOptions)
291{
292    uint32_t id = 0;
293    pthread_mutex_lock(&gDataMutex);
294
295    auto it = gData.clientData.find(this);
296    if (it != gData.clientData.end()) {
297        if (gData.flpInterface != NULL && locationOptions.minDistance > 0) {
298            id = gData.flpInterface->startTracking(this, locationOptions);
299        } else if (gData.gnssInterface != NULL && needsGnssTrackingInfo(it->second)) {
300            id = gData.gnssInterface->startTracking(this, locationOptions);
301        } else if (gData.flpInterface != NULL) {
302            id = gData.flpInterface->startTracking(this, locationOptions);
303        } else if (gData.gnssInterface != NULL) {
304            id = gData.gnssInterface->startTracking(this, locationOptions);
305        } else {
306            LOC_LOGE("%s:%d]: No gnss/flp interface available for Location API client %p ",
307                     __func__, __LINE__, this);
308        }
309    } else {
310        LOC_LOGE("%s:%d]: Location API client %p not found in client data",
311                 __func__, __LINE__, this);
312    }
313
314    pthread_mutex_unlock(&gDataMutex);
315    return id;
316}
317
318void
319LocationAPI::stopTracking(uint32_t id)
320{
321    pthread_mutex_lock(&gDataMutex);
322
323    auto it = gData.clientData.find(this);
324    if (it != gData.clientData.end()) {
325        // we don't know if tracking was started on flp or gnss, so we call stop on both, where
326        // stopTracking call to the incorrect interface will fail without response back to client
327        if (gData.gnssInterface != NULL) {
328            gData.gnssInterface->stopTracking(this, id);
329        }
330        if (gData.flpInterface != NULL) {
331            gData.flpInterface->stopTracking(this, id);
332        }
333        if (gData.flpInterface == NULL && gData.gnssInterface == NULL) {
334            LOC_LOGE("%s:%d]: No gnss/flp interface available for Location API client %p ",
335                     __func__, __LINE__, this);
336        }
337    } else {
338        LOC_LOGE("%s:%d]: Location API client %p not found in client data",
339                 __func__, __LINE__, this);
340    }
341
342    pthread_mutex_unlock(&gDataMutex);
343}
344
345void
346LocationAPI::updateTrackingOptions(uint32_t id, LocationOptions& locationOptions)
347{
348    pthread_mutex_lock(&gDataMutex);
349
350    auto it = gData.clientData.find(this);
351    if (it != gData.clientData.end()) {
352        // we don't know if tracking was started on flp or gnss, so we call update on both, where
353        // updateTracking call to the incorrect interface will fail without response back to client
354        if (gData.gnssInterface != NULL) {
355            gData.gnssInterface->updateTrackingOptions(this, id, locationOptions);
356        }
357        if (gData.flpInterface != NULL) {
358            gData.flpInterface->updateTrackingOptions(this, id, locationOptions);
359        }
360        if (gData.flpInterface == NULL && gData.gnssInterface == NULL) {
361            LOC_LOGE("%s:%d]: No gnss/flp interface available for Location API client %p ",
362                     __func__, __LINE__, this);
363        }
364    } else {
365        LOC_LOGE("%s:%d]: Location API client %p not found in client data",
366                 __func__, __LINE__, this);
367    }
368
369    pthread_mutex_unlock(&gDataMutex);
370}
371
372uint32_t
373LocationAPI::startBatching(LocationOptions& locationOptions)
374{
375    uint32_t id = 0;
376    pthread_mutex_lock(&gDataMutex);
377
378    if (gData.flpInterface != NULL) {
379        id = gData.flpInterface->startBatching(this, locationOptions);
380    } else {
381        LOC_LOGE("%s:%d]: No flp interface available for Location API client %p ",
382                 __func__, __LINE__, this);
383    }
384
385    pthread_mutex_unlock(&gDataMutex);
386    return id;
387}
388
389void
390LocationAPI::stopBatching(uint32_t id)
391{
392    pthread_mutex_lock(&gDataMutex);
393
394    if (gData.flpInterface != NULL) {
395        gData.flpInterface->stopBatching(this, id);
396    } else {
397        LOC_LOGE("%s:%d]: No flp interface available for Location API client %p ",
398                 __func__, __LINE__, this);
399    }
400
401    pthread_mutex_unlock(&gDataMutex);
402}
403
404void
405LocationAPI::updateBatchingOptions(uint32_t id, LocationOptions& locationOptions)
406{
407    pthread_mutex_lock(&gDataMutex);
408
409    if (gData.flpInterface != NULL) {
410        gData.flpInterface->updateBatchingOptions(this,
411                                                  id,
412                                                  locationOptions);
413    } else {
414        LOC_LOGE("%s:%d]: No flp interface available for Location API client %p ",
415                 __func__, __LINE__, this);
416    }
417
418    pthread_mutex_unlock(&gDataMutex);
419}
420
421void
422LocationAPI::getBatchedLocations(uint32_t id, size_t count)
423{
424    pthread_mutex_lock(&gDataMutex);
425
426    if (gData.flpInterface != NULL) {
427        gData.flpInterface->getBatchedLocations(this, id, count);
428    } else {
429        LOC_LOGE("%s:%d]: No flp interface available for Location API client %p ",
430                 __func__, __LINE__, this);
431    }
432
433    pthread_mutex_unlock(&gDataMutex);
434}
435
436uint32_t*
437LocationAPI::addGeofences(size_t count, GeofenceOption* options, GeofenceInfo* info)
438{
439    uint32_t* ids = NULL;
440    pthread_mutex_lock(&gDataMutex);
441
442    if (gData.geofenceInterface != NULL) {
443        ids = gData.geofenceInterface->addGeofences(this, count, options, info);
444    } else {
445        LOC_LOGE("%s:%d]: No geofence interface available for Location API client %p ",
446                 __func__, __LINE__, this);
447    }
448
449    pthread_mutex_unlock(&gDataMutex);
450    return ids;
451}
452
453void
454LocationAPI::removeGeofences(size_t count, uint32_t* ids)
455{
456    pthread_mutex_lock(&gDataMutex);
457
458    if (gData.geofenceInterface != NULL) {
459        gData.geofenceInterface->removeGeofences(this, count, ids);
460    } else {
461        LOC_LOGE("%s:%d]: No geofence interface available for Location API client %p ",
462                 __func__, __LINE__, this);
463    }
464
465    pthread_mutex_unlock(&gDataMutex);
466}
467
468void
469LocationAPI::modifyGeofences(size_t count, uint32_t* ids, GeofenceOption* options)
470{
471    pthread_mutex_lock(&gDataMutex);
472
473    if (gData.geofenceInterface != NULL) {
474        gData.geofenceInterface->modifyGeofences(this, count, ids, options);
475    } else {
476        LOC_LOGE("%s:%d]: No geofence interface available for Location API client %p ",
477                 __func__, __LINE__, this);
478    }
479
480    pthread_mutex_unlock(&gDataMutex);
481}
482
483void
484LocationAPI::pauseGeofences(size_t count, uint32_t* ids)
485{
486    pthread_mutex_lock(&gDataMutex);
487
488    if (gData.geofenceInterface != NULL) {
489        gData.geofenceInterface->pauseGeofences(this, count, ids);
490    } else {
491        LOC_LOGE("%s:%d]: No geofence interface available for Location API client %p ",
492                 __func__, __LINE__, this);
493    }
494
495    pthread_mutex_unlock(&gDataMutex);
496}
497
498void
499LocationAPI::resumeGeofences(size_t count, uint32_t* ids)
500{
501    pthread_mutex_lock(&gDataMutex);
502
503    if (gData.geofenceInterface != NULL) {
504        gData.geofenceInterface->resumeGeofences(this, count, ids);
505    } else {
506        LOC_LOGE("%s:%d]: No geofence interface available for Location API client %p ",
507                 __func__, __LINE__, this);
508    }
509
510    pthread_mutex_unlock(&gDataMutex);
511}
512
513void
514LocationAPI::gnssNiResponse(uint32_t id, GnssNiResponse response)
515{
516    pthread_mutex_lock(&gDataMutex);
517
518    if (gData.gnssInterface != NULL) {
519        gData.gnssInterface->gnssNiResponse(this, id, response);
520    } else {
521        LOC_LOGE("%s:%d]: No gnss interface available for Location API client %p ",
522                 __func__, __LINE__, this);
523    }
524
525    pthread_mutex_unlock(&gDataMutex);
526}
527
528LocationControlAPI*
529LocationControlAPI::createInstance(LocationControlCallbacks& locationControlCallbacks)
530{
531    LocationControlAPI* controlAPI = NULL;
532    pthread_mutex_lock(&gDataMutex);
533
534    if (nullptr != locationControlCallbacks.responseCb && NULL == gData.controlAPI) {
535        if (NULL == gData.gnssInterface && !gGnssLoadFailed) {
536            gData.gnssInterface =
537                (GnssInterface*)loadLocationInterface("libgnss.so", "getGnssInterface");
538            if (NULL == gData.gnssInterface) {
539                gGnssLoadFailed = true;
540                LOC_LOGW("%s:%d]: No gnss interface available", __func__, __LINE__);
541            } else {
542                gData.gnssInterface->initialize();
543            }
544        }
545        if (NULL != gData.gnssInterface) {
546            gData.controlAPI = new LocationControlAPI();
547            gData.controlCallbacks = locationControlCallbacks;
548            gData.gnssInterface->setControlCallbacks(locationControlCallbacks);
549            controlAPI = gData.controlAPI;
550        }
551    }
552
553    pthread_mutex_unlock(&gDataMutex);
554    return controlAPI;
555}
556
557void
558LocationControlAPI::destroy()
559{
560    delete this;
561}
562
563LocationControlAPI::LocationControlAPI()
564{
565    LOC_LOGD("LOCATION CONTROL API CONSTRUCTOR");
566}
567
568LocationControlAPI::~LocationControlAPI()
569{
570    LOC_LOGD("LOCATION CONTROL API DESTRUCTOR");
571    pthread_mutex_lock(&gDataMutex);
572
573    gData.controlAPI = NULL;
574
575    pthread_mutex_unlock(&gDataMutex);
576}
577
578uint32_t
579LocationControlAPI::enable(LocationTechnologyType techType)
580{
581    uint32_t id = 0;
582    pthread_mutex_lock(&gDataMutex);
583
584    if (gData.gnssInterface != NULL) {
585        id = gData.gnssInterface->enable(techType);
586    } else {
587        LOC_LOGE("%s:%d]: No gnss interface available for Location Control API client %p ",
588                 __func__, __LINE__, this);
589    }
590
591    pthread_mutex_unlock(&gDataMutex);
592    return id;
593}
594
595void
596LocationControlAPI::disable(uint32_t id)
597{
598    pthread_mutex_lock(&gDataMutex);
599
600    if (gData.gnssInterface != NULL) {
601        gData.gnssInterface->disable(id);
602    } else {
603        LOC_LOGE("%s:%d]: No gnss interface available for Location Control API client %p ",
604                 __func__, __LINE__, this);
605    }
606
607    pthread_mutex_unlock(&gDataMutex);
608}
609
610uint32_t*
611LocationControlAPI::gnssUpdateConfig(GnssConfig config)
612{
613    uint32_t* ids = NULL;
614    pthread_mutex_lock(&gDataMutex);
615
616    if (gData.gnssInterface != NULL) {
617        ids = gData.gnssInterface->gnssUpdateConfig(config);
618    } else {
619        LOC_LOGE("%s:%d]: No gnss interface available for Location Control API client %p ",
620                 __func__, __LINE__, this);
621    }
622
623    pthread_mutex_unlock(&gDataMutex);
624    return ids;
625}
626
627uint32_t
628LocationControlAPI::gnssDeleteAidingData(GnssAidingData& data)
629{
630    uint32_t id = 0;
631    pthread_mutex_lock(&gDataMutex);
632
633    if (gData.gnssInterface != NULL) {
634        id = gData.gnssInterface->gnssDeleteAidingData(data);
635    } else {
636        LOC_LOGE("%s:%d]: No gnss interface available for Location Control API client %p ",
637                 __func__, __LINE__, this);
638    }
639
640    pthread_mutex_unlock(&gDataMutex);
641    return id;
642}
643