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