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