1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the license at 7 * 8 * http://www.apache.org/license/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the license. 15 */ 16 17#define LOG_TAG "FlpHardwareProvider" 18#define LOG_NDEBUG 0 19 20#define WAKE_LOCK_NAME "FLP" 21#define LOCATION_CLASS_NAME "android/location/Location" 22 23#include "jni.h" 24#include "JNIHelp.h" 25#include "android_runtime/AndroidRuntime.h" 26#include "android_runtime/Log.h" 27#include "hardware/fused_location.h" 28#include "hardware_legacy/power.h" 29 30static jobject sCallbacksObj = NULL; 31static JNIEnv *sCallbackEnv = NULL; 32static hw_device_t* sHardwareDevice = NULL; 33 34static jmethodID sSetVersion = NULL; 35static jmethodID sOnLocationReport = NULL; 36static jmethodID sOnDataReport = NULL; 37static jmethodID sOnBatchingCapabilities = NULL; 38static jmethodID sOnBatchingStatus = NULL; 39static jmethodID sOnGeofenceTransition = NULL; 40static jmethodID sOnGeofenceMonitorStatus = NULL; 41static jmethodID sOnGeofenceAdd = NULL; 42static jmethodID sOnGeofenceRemove = NULL; 43static jmethodID sOnGeofencePause = NULL; 44static jmethodID sOnGeofenceResume = NULL; 45static jmethodID sOnGeofencingCapabilities = NULL; 46 47static const FlpLocationInterface* sFlpInterface = NULL; 48static const FlpDiagnosticInterface* sFlpDiagnosticInterface = NULL; 49static const FlpGeofencingInterface* sFlpGeofencingInterface = NULL; 50static const FlpDeviceContextInterface* sFlpDeviceContextInterface = NULL; 51 52namespace android { 53 54static inline void CheckExceptions(JNIEnv* env, const char* methodName) { 55 if(!env->ExceptionCheck()) { 56 return; 57 } 58 59 ALOGE("An exception was thrown by '%s'.", methodName); 60 LOGE_EX(env); 61 env->ExceptionClear(); 62} 63 64static inline void ThrowOnError( 65 JNIEnv* env, 66 int resultCode, 67 const char* methodName) { 68 if(resultCode == FLP_RESULT_SUCCESS) { 69 return; 70 } 71 72 ALOGE("Error %d in '%s'", resultCode, methodName); 73 // TODO: this layer needs to be refactored to return error codes to Java 74 // raising a FatalError is harsh, and because FLP Hardware Provider is loaded inside the system 75 // service, it can cause the device to reboot, or remain in a reboot loop 76 // a simple exception is still dumped to logcat, but it is handled more gracefully 77 jclass exceptionClass = env->FindClass("java/lang/RuntimeException"); 78 env->ThrowNew(exceptionClass, methodName); 79} 80 81static bool IsValidCallbackThread() { 82 JNIEnv* env = AndroidRuntime::getJNIEnv(); 83 84 if(sCallbackEnv == NULL || sCallbackEnv != env) { 85 ALOGE("CallbackThread check fail: env=%p, expected=%p", env, sCallbackEnv); 86 return false; 87 } 88 89 return true; 90} 91 92static void BatchingCapabilitiesCallback(int32_t capabilities) { 93 if(!IsValidCallbackThread()) { 94 return; 95 } 96 97 sCallbackEnv->CallVoidMethod( 98 sCallbacksObj, 99 sOnBatchingCapabilities, 100 capabilities 101 ); 102 CheckExceptions(sCallbackEnv, __FUNCTION__); 103} 104 105static void BatchingStatusCallback(int32_t status) { 106 if(!IsValidCallbackThread()) { 107 return; 108 } 109 110 sCallbackEnv->CallVoidMethod( 111 sCallbacksObj, 112 sOnBatchingStatus, 113 status 114 ); 115 CheckExceptions(sCallbackEnv, __FUNCTION__); 116} 117 118static int SetThreadEvent(ThreadEvent event) { 119 JavaVM* javaVm = AndroidRuntime::getJavaVM(); 120 121 switch(event) { 122 case ASSOCIATE_JVM: 123 { 124 if(sCallbackEnv != NULL) { 125 ALOGE( 126 "Attempted to associate callback in '%s'. Callback already associated.", 127 __FUNCTION__ 128 ); 129 return FLP_RESULT_ERROR; 130 } 131 132 JavaVMAttachArgs args = { 133 JNI_VERSION_1_6, 134 "FLP Service Callback Thread", 135 /* group */ NULL 136 }; 137 138 jint attachResult = javaVm->AttachCurrentThread(&sCallbackEnv, &args); 139 if (attachResult != 0) { 140 ALOGE("Callback thread attachment error: %d", attachResult); 141 return FLP_RESULT_ERROR; 142 } 143 144 ALOGV("Callback thread attached: %p", sCallbackEnv); 145 146 // Send the version to the upper layer. 147 sCallbackEnv->CallVoidMethod( 148 sCallbacksObj, 149 sSetVersion, 150 sFlpInterface->size == sizeof(FlpLocationInterface) ? 2 : 1 151 ); 152 CheckExceptions(sCallbackEnv, __FUNCTION__); 153 break; 154 } 155 case DISASSOCIATE_JVM: 156 { 157 if (!IsValidCallbackThread()) { 158 ALOGE( 159 "Attempted to dissasociate an unnownk callback thread : '%s'.", 160 __FUNCTION__ 161 ); 162 return FLP_RESULT_ERROR; 163 } 164 165 if (javaVm->DetachCurrentThread() != 0) { 166 return FLP_RESULT_ERROR; 167 } 168 169 sCallbackEnv = NULL; 170 break; 171 } 172 default: 173 ALOGE("Invalid ThreadEvent request %d", event); 174 return FLP_RESULT_ERROR; 175 } 176 177 return FLP_RESULT_SUCCESS; 178} 179 180/* 181 * Initializes the FlpHardwareProvider class from the native side by opening 182 * the HW module and obtaining the proper interfaces. 183 */ 184static void ClassInit(JNIEnv* env, jclass clazz) { 185 sFlpInterface = NULL; 186 187 // get references to the Java provider methods 188 sSetVersion = env->GetMethodID( 189 clazz, 190 "setVersion", 191 "(I)V"); 192 sOnLocationReport = env->GetMethodID( 193 clazz, 194 "onLocationReport", 195 "([Landroid/location/Location;)V"); 196 sOnDataReport = env->GetMethodID( 197 clazz, 198 "onDataReport", 199 "(Ljava/lang/String;)V" 200 ); 201 sOnBatchingCapabilities = env->GetMethodID( 202 clazz, 203 "onBatchingCapabilities", 204 "(I)V"); 205 sOnBatchingStatus = env->GetMethodID( 206 clazz, 207 "onBatchingStatus", 208 "(I)V"); 209 sOnGeofencingCapabilities = env->GetMethodID( 210 clazz, 211 "onGeofencingCapabilities", 212 "(I)V"); 213 sOnGeofenceTransition = env->GetMethodID( 214 clazz, 215 "onGeofenceTransition", 216 "(ILandroid/location/Location;IJI)V" 217 ); 218 sOnGeofenceMonitorStatus = env->GetMethodID( 219 clazz, 220 "onGeofenceMonitorStatus", 221 "(IILandroid/location/Location;)V" 222 ); 223 sOnGeofenceAdd = env->GetMethodID(clazz, "onGeofenceAdd", "(II)V"); 224 sOnGeofenceRemove = env->GetMethodID(clazz, "onGeofenceRemove", "(II)V"); 225 sOnGeofencePause = env->GetMethodID(clazz, "onGeofencePause", "(II)V"); 226 sOnGeofenceResume = env->GetMethodID(clazz, "onGeofenceResume", "(II)V"); 227 228 // open the hardware module 229 const hw_module_t* module = NULL; 230 int err = hw_get_module(FUSED_LOCATION_HARDWARE_MODULE_ID, &module); 231 if (err != 0) { 232 ALOGE("Error hw_get_module '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err); 233 return; 234 } 235 236 err = module->methods->open( 237 module, 238 FUSED_LOCATION_HARDWARE_MODULE_ID, 239 &sHardwareDevice); 240 if (err != 0) { 241 ALOGE("Error opening device '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err); 242 return; 243 } 244 245 // acquire the interfaces pointers 246 flp_device_t* flp_device = reinterpret_cast<flp_device_t*>(sHardwareDevice); 247 sFlpInterface = flp_device->get_flp_interface(flp_device); 248 249 if (sFlpInterface != NULL) { 250 sFlpDiagnosticInterface = reinterpret_cast<const FlpDiagnosticInterface*>( 251 sFlpInterface->get_extension(FLP_DIAGNOSTIC_INTERFACE)); 252 253 sFlpGeofencingInterface = reinterpret_cast<const FlpGeofencingInterface*>( 254 sFlpInterface->get_extension(FLP_GEOFENCING_INTERFACE)); 255 256 sFlpDeviceContextInterface = reinterpret_cast<const FlpDeviceContextInterface*>( 257 sFlpInterface->get_extension(FLP_DEVICE_CONTEXT_INTERFACE)); 258 } 259} 260 261/* 262 * Helper function to unwrap a java object back into a FlpLocation structure. 263 */ 264static void TranslateFromObject( 265 JNIEnv* env, 266 jobject locationObject, 267 FlpLocation& location) { 268 location.size = sizeof(FlpLocation); 269 location.flags = 0; 270 271 jclass locationClass = env->GetObjectClass(locationObject); 272 273 jmethodID getLatitude = env->GetMethodID(locationClass, "getLatitude", "()D"); 274 location.latitude = env->CallDoubleMethod(locationObject, getLatitude); 275 jmethodID getLongitude = env->GetMethodID(locationClass, "getLongitude", "()D"); 276 location.longitude = env->CallDoubleMethod(locationObject, getLongitude); 277 jmethodID getTime = env->GetMethodID(locationClass, "getTime", "()J"); 278 location.timestamp = env->CallLongMethod(locationObject, getTime); 279 location.flags |= FLP_LOCATION_HAS_LAT_LONG; 280 281 jmethodID hasAltitude = env->GetMethodID(locationClass, "hasAltitude", "()Z"); 282 if (env->CallBooleanMethod(locationObject, hasAltitude)) { 283 jmethodID getAltitude = env->GetMethodID(locationClass, "getAltitude", "()D"); 284 location.altitude = env->CallDoubleMethod(locationObject, getAltitude); 285 location.flags |= FLP_LOCATION_HAS_ALTITUDE; 286 } 287 288 jmethodID hasSpeed = env->GetMethodID(locationClass, "hasSpeed", "()Z"); 289 if (env->CallBooleanMethod(locationObject, hasSpeed)) { 290 jmethodID getSpeed = env->GetMethodID(locationClass, "getSpeed", "()F"); 291 location.speed = env->CallFloatMethod(locationObject, getSpeed); 292 location.flags |= FLP_LOCATION_HAS_SPEED; 293 } 294 295 jmethodID hasBearing = env->GetMethodID(locationClass, "hasBearing", "()Z"); 296 if (env->CallBooleanMethod(locationObject, hasBearing)) { 297 jmethodID getBearing = env->GetMethodID(locationClass, "getBearing", "()F"); 298 location.bearing = env->CallFloatMethod(locationObject, getBearing); 299 location.flags |= FLP_LOCATION_HAS_BEARING; 300 } 301 302 jmethodID hasAccuracy = env->GetMethodID(locationClass, "hasAccuracy", "()Z"); 303 if (env->CallBooleanMethod(locationObject, hasAccuracy)) { 304 jmethodID getAccuracy = env->GetMethodID( 305 locationClass, 306 "getAccuracy", 307 "()F" 308 ); 309 location.accuracy = env->CallFloatMethod(locationObject, getAccuracy); 310 location.flags |= FLP_LOCATION_HAS_ACCURACY; 311 } 312 313 // TODO: wire sources_used if Location class exposes them 314 315 env->DeleteLocalRef(locationClass); 316} 317 318/* 319 * Helper function to unwrap FlpBatchOptions from the Java Runtime calls. 320 */ 321static void TranslateFromObject( 322 JNIEnv* env, 323 jobject batchOptionsObject, 324 FlpBatchOptions& batchOptions) { 325 jclass batchOptionsClass = env->GetObjectClass(batchOptionsObject); 326 327 jmethodID getMaxPower = env->GetMethodID( 328 batchOptionsClass, 329 "getMaxPowerAllocationInMW", 330 "()D" 331 ); 332 batchOptions.max_power_allocation_mW = env->CallDoubleMethod( 333 batchOptionsObject, 334 getMaxPower 335 ); 336 337 jmethodID getPeriod = env->GetMethodID( 338 batchOptionsClass, 339 "getPeriodInNS", 340 "()J" 341 ); 342 batchOptions.period_ns = env->CallLongMethod(batchOptionsObject, getPeriod); 343 344 jmethodID getSourcesToUse = env->GetMethodID( 345 batchOptionsClass, 346 "getSourcesToUse", 347 "()I" 348 ); 349 batchOptions.sources_to_use = env->CallIntMethod( 350 batchOptionsObject, 351 getSourcesToUse 352 ); 353 354 jmethodID getSmallestDisplacementMeters = env->GetMethodID( 355 batchOptionsClass, 356 "getSmallestDisplacementMeters", 357 "()F" 358 ); 359 batchOptions.smallest_displacement_meters 360 = env->CallFloatMethod(batchOptionsObject, getSmallestDisplacementMeters); 361 362 jmethodID getFlags = env->GetMethodID(batchOptionsClass, "getFlags", "()I"); 363 batchOptions.flags = env->CallIntMethod(batchOptionsObject, getFlags); 364 365 env->DeleteLocalRef(batchOptionsClass); 366} 367 368/* 369 * Helper function to unwrap Geofence structures from the Java Runtime calls. 370 */ 371static void TranslateGeofenceFromGeofenceHardwareRequestParcelable( 372 JNIEnv* env, 373 jobject geofenceRequestObject, 374 Geofence& geofence) { 375 jclass geofenceRequestClass = env->GetObjectClass(geofenceRequestObject); 376 377 jmethodID getId = env->GetMethodID(geofenceRequestClass, "getId", "()I"); 378 geofence.geofence_id = env->CallIntMethod(geofenceRequestObject, getId); 379 380 jmethodID getType = env->GetMethodID(geofenceRequestClass, "getType", "()I"); 381 // this works because GeofenceHardwareRequest.java and fused_location.h have 382 // the same notion of geofence types 383 GeofenceType type = (GeofenceType)env->CallIntMethod(geofenceRequestObject, getType); 384 if(type != TYPE_CIRCLE) { 385 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 386 } 387 geofence.data->type = type; 388 GeofenceCircle& circle = geofence.data->geofence.circle; 389 390 jmethodID getLatitude = env->GetMethodID( 391 geofenceRequestClass, 392 "getLatitude", 393 "()D"); 394 circle.latitude = env->CallDoubleMethod(geofenceRequestObject, getLatitude); 395 396 jmethodID getLongitude = env->GetMethodID( 397 geofenceRequestClass, 398 "getLongitude", 399 "()D"); 400 circle.longitude = env->CallDoubleMethod(geofenceRequestObject, getLongitude); 401 402 jmethodID getRadius = env->GetMethodID(geofenceRequestClass, "getRadius", "()D"); 403 circle.radius_m = env->CallDoubleMethod(geofenceRequestObject, getRadius); 404 405 GeofenceOptions* options = geofence.options; 406 jmethodID getMonitorTransitions = env->GetMethodID( 407 geofenceRequestClass, 408 "getMonitorTransitions", 409 "()I"); 410 options->monitor_transitions = env->CallIntMethod( 411 geofenceRequestObject, 412 getMonitorTransitions); 413 414 jmethodID getUnknownTimer = env->GetMethodID( 415 geofenceRequestClass, 416 "getUnknownTimer", 417 "()I"); 418 options->unknown_timer_ms = env->CallIntMethod(geofenceRequestObject, getUnknownTimer); 419 420 jmethodID getNotificationResponsiveness = env->GetMethodID( 421 geofenceRequestClass, 422 "getNotificationResponsiveness", 423 "()I"); 424 options->notification_responsivenes_ms = env->CallIntMethod( 425 geofenceRequestObject, 426 getNotificationResponsiveness); 427 428 jmethodID getLastTransition = env->GetMethodID( 429 geofenceRequestClass, 430 "getLastTransition", 431 "()I"); 432 options->last_transition = env->CallIntMethod(geofenceRequestObject, getLastTransition); 433 434 jmethodID getSourceTechnologies = 435 env->GetMethodID(geofenceRequestClass, "getSourceTechnologies", "()I"); 436 options->sources_to_use = env->CallIntMethod(geofenceRequestObject, getSourceTechnologies); 437 438 env->DeleteLocalRef(geofenceRequestClass); 439} 440 441/* 442 * Helper function to transform FlpLocation into a java object. 443 */ 444static void TranslateToObject(const FlpLocation* location, jobject& locationObject) { 445 jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME); 446 jmethodID locationCtor = sCallbackEnv->GetMethodID( 447 locationClass, 448 "<init>", 449 "(Ljava/lang/String;)V" 450 ); 451 452 // the provider is set in the upper JVM layer 453 locationObject = sCallbackEnv->NewObject(locationClass, locationCtor, NULL); 454 jint flags = location->flags; 455 456 // set the valid information in the object 457 if (flags & FLP_LOCATION_HAS_LAT_LONG) { 458 jmethodID setLatitude = sCallbackEnv->GetMethodID( 459 locationClass, 460 "setLatitude", 461 "(D)V" 462 ); 463 sCallbackEnv->CallVoidMethod(locationObject, setLatitude, location->latitude); 464 465 jmethodID setLongitude = sCallbackEnv->GetMethodID( 466 locationClass, 467 "setLongitude", 468 "(D)V" 469 ); 470 sCallbackEnv->CallVoidMethod( 471 locationObject, 472 setLongitude, 473 location->longitude 474 ); 475 476 jmethodID setTime = sCallbackEnv->GetMethodID( 477 locationClass, 478 "setTime", 479 "(J)V" 480 ); 481 sCallbackEnv->CallVoidMethod(locationObject, setTime, location->timestamp); 482 } 483 484 if (flags & FLP_LOCATION_HAS_ALTITUDE) { 485 jmethodID setAltitude = sCallbackEnv->GetMethodID( 486 locationClass, 487 "setAltitude", 488 "(D)V" 489 ); 490 sCallbackEnv->CallVoidMethod(locationObject, setAltitude, location->altitude); 491 } 492 493 if (flags & FLP_LOCATION_HAS_SPEED) { 494 jmethodID setSpeed = sCallbackEnv->GetMethodID( 495 locationClass, 496 "setSpeed", 497 "(F)V" 498 ); 499 sCallbackEnv->CallVoidMethod(locationObject, setSpeed, location->speed); 500 } 501 502 if (flags & FLP_LOCATION_HAS_BEARING) { 503 jmethodID setBearing = sCallbackEnv->GetMethodID( 504 locationClass, 505 "setBearing", 506 "(F)V" 507 ); 508 sCallbackEnv->CallVoidMethod(locationObject, setBearing, location->bearing); 509 } 510 511 if (flags & FLP_LOCATION_HAS_ACCURACY) { 512 jmethodID setAccuracy = sCallbackEnv->GetMethodID( 513 locationClass, 514 "setAccuracy", 515 "(F)V" 516 ); 517 sCallbackEnv->CallVoidMethod(locationObject, setAccuracy, location->accuracy); 518 } 519 520 // TODO: wire FlpLocation::sources_used when needed 521 522 sCallbackEnv->DeleteLocalRef(locationClass); 523} 524 525/* 526 * Helper function to serialize FlpLocation structures. 527 */ 528static void TranslateToObjectArray( 529 int32_t locationsCount, 530 FlpLocation** locations, 531 jobjectArray& locationsArray) { 532 jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME); 533 locationsArray = sCallbackEnv->NewObjectArray( 534 locationsCount, 535 locationClass, 536 /* initialElement */ NULL 537 ); 538 539 for (int i = 0; i < locationsCount; ++i) { 540 jobject locationObject = NULL; 541 TranslateToObject(locations[i], locationObject); 542 sCallbackEnv->SetObjectArrayElement(locationsArray, i, locationObject); 543 sCallbackEnv->DeleteLocalRef(locationObject); 544 } 545 546 sCallbackEnv->DeleteLocalRef(locationClass); 547} 548 549static void LocationCallback(int32_t locationsCount, FlpLocation** locations) { 550 if(!IsValidCallbackThread()) { 551 return; 552 } 553 554 if(locationsCount == 0 || locations == NULL) { 555 ALOGE( 556 "Invalid LocationCallback. Count: %d, Locations: %p", 557 locationsCount, 558 locations 559 ); 560 return; 561 } 562 563 jobjectArray locationsArray = NULL; 564 TranslateToObjectArray(locationsCount, locations, locationsArray); 565 566 sCallbackEnv->CallVoidMethod( 567 sCallbacksObj, 568 sOnLocationReport, 569 locationsArray 570 ); 571 CheckExceptions(sCallbackEnv, __FUNCTION__); 572 573 if(locationsArray != NULL) { 574 sCallbackEnv->DeleteLocalRef(locationsArray); 575 } 576} 577 578static void AcquireWakelock() { 579 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME); 580} 581 582static void ReleaseWakelock() { 583 release_wake_lock(WAKE_LOCK_NAME); 584} 585 586FlpCallbacks sFlpCallbacks = { 587 sizeof(FlpCallbacks), 588 LocationCallback, 589 AcquireWakelock, 590 ReleaseWakelock, 591 SetThreadEvent, 592 BatchingCapabilitiesCallback, 593 BatchingStatusCallback 594}; 595 596static void ReportData(char* data, int length) { 597 jstring stringData = NULL; 598 599 if(length != 0 && data != NULL) { 600 stringData = sCallbackEnv->NewString(reinterpret_cast<jchar*>(data), length); 601 } else { 602 ALOGE("Invalid ReportData callback. Length: %d, Data: %p", length, data); 603 return; 604 } 605 606 sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnDataReport, stringData); 607 CheckExceptions(sCallbackEnv, __FUNCTION__); 608} 609 610FlpDiagnosticCallbacks sFlpDiagnosticCallbacks = { 611 sizeof(FlpDiagnosticCallbacks), 612 SetThreadEvent, 613 ReportData 614}; 615 616static void GeofenceTransitionCallback( 617 int32_t geofenceId, 618 FlpLocation* location, 619 int32_t transition, 620 FlpUtcTime timestamp, 621 uint32_t sourcesUsed 622 ) { 623 if(!IsValidCallbackThread()) { 624 return; 625 } 626 627 if(location == NULL) { 628 ALOGE("GeofenceTransition received with invalid location: %p", location); 629 return; 630 } 631 632 jobject locationObject = NULL; 633 TranslateToObject(location, locationObject); 634 635 sCallbackEnv->CallVoidMethod( 636 sCallbacksObj, 637 sOnGeofenceTransition, 638 geofenceId, 639 locationObject, 640 transition, 641 timestamp, 642 sourcesUsed 643 ); 644 CheckExceptions(sCallbackEnv, __FUNCTION__); 645 646 if(locationObject != NULL) { 647 sCallbackEnv->DeleteLocalRef(locationObject); 648 } 649} 650 651static void GeofenceMonitorStatusCallback( 652 int32_t status, 653 uint32_t source, 654 FlpLocation* lastLocation) { 655 if(!IsValidCallbackThread()) { 656 return; 657 } 658 659 jobject locationObject = NULL; 660 if(lastLocation != NULL) { 661 TranslateToObject(lastLocation, locationObject); 662 } 663 664 sCallbackEnv->CallVoidMethod( 665 sCallbacksObj, 666 sOnGeofenceMonitorStatus, 667 status, 668 source, 669 locationObject 670 ); 671 CheckExceptions(sCallbackEnv, __FUNCTION__); 672 673 if(locationObject != NULL) { 674 sCallbackEnv->DeleteLocalRef(locationObject); 675 } 676} 677 678static void GeofenceAddCallback(int32_t geofenceId, int32_t result) { 679 if(!IsValidCallbackThread()) { 680 return; 681 } 682 683 sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnGeofenceAdd, geofenceId, result); 684 CheckExceptions(sCallbackEnv, __FUNCTION__); 685} 686 687static void GeofenceRemoveCallback(int32_t geofenceId, int32_t result) { 688 if(!IsValidCallbackThread()) { 689 return; 690 } 691 692 sCallbackEnv->CallVoidMethod( 693 sCallbacksObj, 694 sOnGeofenceRemove, 695 geofenceId, 696 result 697 ); 698 CheckExceptions(sCallbackEnv, __FUNCTION__); 699} 700 701static void GeofencePauseCallback(int32_t geofenceId, int32_t result) { 702 if(!IsValidCallbackThread()) { 703 return; 704 } 705 706 sCallbackEnv->CallVoidMethod( 707 sCallbacksObj, 708 sOnGeofencePause, 709 geofenceId, 710 result 711 ); 712 CheckExceptions(sCallbackEnv, __FUNCTION__); 713} 714 715static void GeofenceResumeCallback(int32_t geofenceId, int32_t result) { 716 if(!IsValidCallbackThread()) { 717 return; 718 } 719 720 sCallbackEnv->CallVoidMethod( 721 sCallbacksObj, 722 sOnGeofenceResume, 723 geofenceId, 724 result 725 ); 726 CheckExceptions(sCallbackEnv, __FUNCTION__); 727} 728 729static void GeofencingCapabilitiesCallback(int32_t capabilities) { 730 if(!IsValidCallbackThread()) { 731 return; 732 } 733 734 sCallbackEnv->CallVoidMethod( 735 sCallbacksObj, 736 sOnGeofencingCapabilities, 737 capabilities 738 ); 739 CheckExceptions(sCallbackEnv, __FUNCTION__); 740} 741 742FlpGeofenceCallbacks sFlpGeofenceCallbacks = { 743 sizeof(FlpGeofenceCallbacks), 744 GeofenceTransitionCallback, 745 GeofenceMonitorStatusCallback, 746 GeofenceAddCallback, 747 GeofenceRemoveCallback, 748 GeofencePauseCallback, 749 GeofenceResumeCallback, 750 SetThreadEvent, 751 GeofencingCapabilitiesCallback 752}; 753 754/* 755 * Initializes the Fused Location Provider in the native side. It ensures that 756 * the Flp interfaces are initialized properly. 757 */ 758static void Init(JNIEnv* env, jobject obj) { 759 if(sCallbacksObj == NULL) { 760 sCallbacksObj = env->NewGlobalRef(obj); 761 } 762 763 // initialize the Flp interfaces 764 if(sFlpInterface == NULL || sFlpInterface->init(&sFlpCallbacks) != 0) { 765 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 766 } 767 768 if(sFlpDiagnosticInterface != NULL) { 769 sFlpDiagnosticInterface->init(&sFlpDiagnosticCallbacks); 770 } 771 772 if(sFlpGeofencingInterface != NULL) { 773 sFlpGeofencingInterface->init(&sFlpGeofenceCallbacks); 774 } 775 776 // TODO: inject any device context if when needed 777} 778 779static jboolean IsSupported(JNIEnv* /* env */, jclass /* clazz */) { 780 if (sFlpInterface == NULL) { 781 return JNI_FALSE; 782 } 783 return JNI_TRUE; 784} 785 786static jint GetBatchSize(JNIEnv* env, jobject /* object */) { 787 if(sFlpInterface == NULL) { 788 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 789 } 790 791 return sFlpInterface->get_batch_size(); 792} 793 794static void StartBatching( 795 JNIEnv* env, 796 jobject /* object */, 797 jint id, 798 jobject optionsObject) { 799 if(sFlpInterface == NULL || optionsObject == NULL) { 800 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 801 } 802 803 FlpBatchOptions options; 804 TranslateFromObject(env, optionsObject, options); 805 int result = sFlpInterface->start_batching(id, &options); 806 ThrowOnError(env, result, __FUNCTION__); 807} 808 809static void UpdateBatchingOptions( 810 JNIEnv* env, 811 jobject /* object */, 812 jint id, 813 jobject optionsObject) { 814 if(sFlpInterface == NULL || optionsObject == NULL) { 815 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 816 } 817 818 FlpBatchOptions options; 819 TranslateFromObject(env, optionsObject, options); 820 int result = sFlpInterface->update_batching_options(id, &options); 821 ThrowOnError(env, result, __FUNCTION__); 822} 823 824static void StopBatching(JNIEnv* env, jobject /* object */, jint id) { 825 if(sFlpInterface == NULL) { 826 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 827 } 828 829 sFlpInterface->stop_batching(id); 830} 831 832static void Cleanup(JNIEnv* env, jobject /* object */) { 833 if(sFlpInterface == NULL) { 834 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 835 } 836 837 sFlpInterface->cleanup(); 838 839 if(sCallbacksObj != NULL) { 840 env->DeleteGlobalRef(sCallbacksObj); 841 sCallbacksObj = NULL; 842 } 843 844 sFlpInterface = NULL; 845 sFlpDiagnosticInterface = NULL; 846 sFlpDeviceContextInterface = NULL; 847 sFlpGeofencingInterface = NULL; 848 849 if(sHardwareDevice != NULL) { 850 sHardwareDevice->close(sHardwareDevice); 851 sHardwareDevice = NULL; 852 } 853} 854 855static void GetBatchedLocation(JNIEnv* env, jobject /* object */, jint lastNLocations) { 856 if(sFlpInterface == NULL) { 857 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 858 } 859 860 sFlpInterface->get_batched_location(lastNLocations); 861} 862 863static void FlushBatchedLocations(JNIEnv* env, jobject /* object */) { 864 if(sFlpInterface == NULL) { 865 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 866 } 867 868 sFlpInterface->flush_batched_locations(); 869} 870 871static void InjectLocation(JNIEnv* env, jobject /* object */, jobject locationObject) { 872 if(locationObject == NULL) { 873 ALOGE("Invalid location for injection: %p", locationObject); 874 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 875 } 876 877 if(sFlpInterface == NULL) { 878 // there is no listener, bail 879 return; 880 } 881 882 FlpLocation location; 883 TranslateFromObject(env, locationObject, location); 884 int result = sFlpInterface->inject_location(&location); 885 if (result != FLP_RESULT_SUCCESS) { 886 // do not throw but log, this operation should be fire and forget 887 ALOGE("Error %d in '%s'", result, __FUNCTION__); 888 } 889} 890 891static jboolean IsDiagnosticSupported() { 892 return sFlpDiagnosticInterface != NULL; 893} 894 895static void InjectDiagnosticData(JNIEnv* env, jobject /* object */, jstring stringData) { 896 if(stringData == NULL) { 897 ALOGE("Invalid diagnostic data for injection: %p", stringData); 898 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 899 } 900 901 if(sFlpDiagnosticInterface == NULL) { 902 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 903 } 904 905 int length = env->GetStringLength(stringData); 906 const jchar* data = env->GetStringChars(stringData, /* isCopy */ NULL); 907 if(data == NULL) { 908 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 909 } 910 911 int result = sFlpDiagnosticInterface->inject_data((char*) data, length); 912 ThrowOnError(env, result, __FUNCTION__); 913} 914 915static jboolean IsDeviceContextSupported() { 916 return sFlpDeviceContextInterface != NULL; 917} 918 919static void InjectDeviceContext(JNIEnv* env, jobject /* object */, jint enabledMask) { 920 if(sFlpDeviceContextInterface == NULL) { 921 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 922 } 923 924 int result = sFlpDeviceContextInterface->inject_device_context(enabledMask); 925 ThrowOnError(env, result, __FUNCTION__); 926} 927 928static jboolean IsGeofencingSupported() { 929 return sFlpGeofencingInterface != NULL; 930} 931 932static void AddGeofences( 933 JNIEnv* env, 934 jobject /* object */, 935 jobjectArray geofenceRequestsArray) { 936 if(geofenceRequestsArray == NULL) { 937 ALOGE("Invalid Geofences to add: %p", geofenceRequestsArray); 938 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 939 } 940 941 if (sFlpGeofencingInterface == NULL) { 942 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 943 } 944 945 jint geofenceRequestsCount = env->GetArrayLength(geofenceRequestsArray); 946 if(geofenceRequestsCount == 0) { 947 return; 948 } 949 950 Geofence* geofences = new Geofence[geofenceRequestsCount]; 951 if (geofences == NULL) { 952 ThrowOnError(env, FLP_RESULT_INSUFFICIENT_MEMORY, __FUNCTION__); 953 } 954 955 for (int i = 0; i < geofenceRequestsCount; ++i) { 956 geofences[i].data = new GeofenceData(); 957 geofences[i].options = new GeofenceOptions(); 958 jobject geofenceObject = env->GetObjectArrayElement(geofenceRequestsArray, i); 959 960 TranslateGeofenceFromGeofenceHardwareRequestParcelable(env, geofenceObject, geofences[i]); 961 env->DeleteLocalRef(geofenceObject); 962 } 963 964 sFlpGeofencingInterface->add_geofences(geofenceRequestsCount, &geofences); 965 if (geofences != NULL) { 966 for(int i = 0; i < geofenceRequestsCount; ++i) { 967 delete geofences[i].data; 968 delete geofences[i].options; 969 } 970 delete[] geofences; 971 } 972} 973 974static void PauseGeofence(JNIEnv* env, jobject /* object */, jint geofenceId) { 975 if(sFlpGeofencingInterface == NULL) { 976 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 977 } 978 979 sFlpGeofencingInterface->pause_geofence(geofenceId); 980} 981 982static void ResumeGeofence( 983 JNIEnv* env, 984 jobject /* object */, 985 jint geofenceId, 986 jint monitorTransitions) { 987 if(sFlpGeofencingInterface == NULL) { 988 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 989 } 990 991 sFlpGeofencingInterface->resume_geofence(geofenceId, monitorTransitions); 992} 993 994static void ModifyGeofenceOption( 995 JNIEnv* env, 996 jobject /* object */, 997 jint geofenceId, 998 jint lastTransition, 999 jint monitorTransitions, 1000 jint notificationResponsiveness, 1001 jint unknownTimer, 1002 jint sourcesToUse) { 1003 if(sFlpGeofencingInterface == NULL) { 1004 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 1005 } 1006 1007 GeofenceOptions options = { 1008 lastTransition, 1009 monitorTransitions, 1010 notificationResponsiveness, 1011 unknownTimer, 1012 (uint32_t)sourcesToUse 1013 }; 1014 1015 sFlpGeofencingInterface->modify_geofence_option(geofenceId, &options); 1016} 1017 1018static void RemoveGeofences( 1019 JNIEnv* env, 1020 jobject /* object */, 1021 jintArray geofenceIdsArray) { 1022 if(sFlpGeofencingInterface == NULL) { 1023 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 1024 } 1025 1026 jsize geofenceIdsCount = env->GetArrayLength(geofenceIdsArray); 1027 jint* geofenceIds = env->GetIntArrayElements(geofenceIdsArray, /* isCopy */ NULL); 1028 if(geofenceIds == NULL) { 1029 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 1030 } 1031 1032 sFlpGeofencingInterface->remove_geofences(geofenceIdsCount, geofenceIds); 1033 env->ReleaseIntArrayElements(geofenceIdsArray, geofenceIds, 0 /*mode*/); 1034} 1035 1036static JNINativeMethod sMethods[] = { 1037 //{"name", "signature", functionPointer } 1038 {"nativeClassInit", "()V", reinterpret_cast<void*>(ClassInit)}, 1039 {"nativeInit", "()V", reinterpret_cast<void*>(Init)}, 1040 {"nativeCleanup", "()V", reinterpret_cast<void*>(Cleanup)}, 1041 {"nativeIsSupported", "()Z", reinterpret_cast<void*>(IsSupported)}, 1042 {"nativeGetBatchSize", "()I", reinterpret_cast<void*>(GetBatchSize)}, 1043 {"nativeStartBatching", 1044 "(ILandroid/location/FusedBatchOptions;)V", 1045 reinterpret_cast<void*>(StartBatching)}, 1046 {"nativeUpdateBatchingOptions", 1047 "(ILandroid/location/FusedBatchOptions;)V", 1048 reinterpret_cast<void*>(UpdateBatchingOptions)}, 1049 {"nativeStopBatching", "(I)V", reinterpret_cast<void*>(StopBatching)}, 1050 {"nativeRequestBatchedLocation", 1051 "(I)V", 1052 reinterpret_cast<void*>(GetBatchedLocation)}, 1053 {"nativeFlushBatchedLocations", 1054 "()V", 1055 reinterpret_cast<void*>(FlushBatchedLocations)}, 1056 {"nativeInjectLocation", 1057 "(Landroid/location/Location;)V", 1058 reinterpret_cast<void*>(InjectLocation)}, 1059 {"nativeIsDiagnosticSupported", 1060 "()Z", 1061 reinterpret_cast<void*>(IsDiagnosticSupported)}, 1062 {"nativeInjectDiagnosticData", 1063 "(Ljava/lang/String;)V", 1064 reinterpret_cast<void*>(InjectDiagnosticData)}, 1065 {"nativeIsDeviceContextSupported", 1066 "()Z", 1067 reinterpret_cast<void*>(IsDeviceContextSupported)}, 1068 {"nativeInjectDeviceContext", 1069 "(I)V", 1070 reinterpret_cast<void*>(InjectDeviceContext)}, 1071 {"nativeIsGeofencingSupported", 1072 "()Z", 1073 reinterpret_cast<void*>(IsGeofencingSupported)}, 1074 {"nativeAddGeofences", 1075 "([Landroid/hardware/location/GeofenceHardwareRequestParcelable;)V", 1076 reinterpret_cast<void*>(AddGeofences)}, 1077 {"nativePauseGeofence", "(I)V", reinterpret_cast<void*>(PauseGeofence)}, 1078 {"nativeResumeGeofence", "(II)V", reinterpret_cast<void*>(ResumeGeofence)}, 1079 {"nativeModifyGeofenceOption", 1080 "(IIIIII)V", 1081 reinterpret_cast<void*>(ModifyGeofenceOption)}, 1082 {"nativeRemoveGeofences", "([I)V", reinterpret_cast<void*>(RemoveGeofences)} 1083}; 1084 1085/* 1086 * Registration method invoked on JNI Load. 1087 */ 1088int register_android_server_location_FlpHardwareProvider(JNIEnv* env) { 1089 return jniRegisterNativeMethods( 1090 env, 1091 "com/android/server/location/FlpHardwareProvider", 1092 sMethods, 1093 NELEM(sMethods) 1094 ); 1095} 1096 1097} /* name-space Android */ 1098