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