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