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