com_android_server_location_FlpHardwareProvider.cpp revision 5ce66d8dcc786b3d6a0fdfb42074e6c9741590ef
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 // TODO: set data.sources_to_use when available 368 369 env->DeleteLocalRef(geofenceRequestClass); 370} 371 372/* 373 * Helper function to transform FlpLocation into a java object. 374 */ 375static void TranslateToObject(const FlpLocation* location, jobject& locationObject) { 376 jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME); 377 jmethodID locationCtor = sCallbackEnv->GetMethodID( 378 locationClass, 379 "<init>", 380 "(Ljava/lang/String;)V" 381 ); 382 383 // the provider is set in the upper JVM layer 384 locationObject = sCallbackEnv->NewObject(locationClass, locationCtor, NULL); 385 jint flags = location->flags; 386 387 // set the valid information in the object 388 if (flags & FLP_LOCATION_HAS_LAT_LONG) { 389 jmethodID setLatitude = sCallbackEnv->GetMethodID( 390 locationClass, 391 "setLatitude", 392 "(D)V" 393 ); 394 sCallbackEnv->CallVoidMethod(locationObject, setLatitude, location->latitude); 395 396 jmethodID setLongitude = sCallbackEnv->GetMethodID( 397 locationClass, 398 "setLongitude", 399 "(D)V" 400 ); 401 sCallbackEnv->CallVoidMethod( 402 locationObject, 403 setLongitude, 404 location->longitude 405 ); 406 407 jmethodID setTime = sCallbackEnv->GetMethodID( 408 locationClass, 409 "setTime", 410 "(J)V" 411 ); 412 sCallbackEnv->CallVoidMethod(locationObject, setTime, location->timestamp); 413 } 414 415 if (flags & FLP_LOCATION_HAS_ALTITUDE) { 416 jmethodID setAltitude = sCallbackEnv->GetMethodID( 417 locationClass, 418 "setAltitude", 419 "(D)V" 420 ); 421 sCallbackEnv->CallVoidMethod(locationObject, setAltitude, location->altitude); 422 } 423 424 if (flags & FLP_LOCATION_HAS_SPEED) { 425 jmethodID setSpeed = sCallbackEnv->GetMethodID( 426 locationClass, 427 "setSpeed", 428 "(F)V" 429 ); 430 sCallbackEnv->CallVoidMethod(locationObject, setSpeed, location->speed); 431 } 432 433 if (flags & FLP_LOCATION_HAS_BEARING) { 434 jmethodID setBearing = sCallbackEnv->GetMethodID( 435 locationClass, 436 "setBearing", 437 "(F)V" 438 ); 439 sCallbackEnv->CallVoidMethod(locationObject, setBearing, location->bearing); 440 } 441 442 if (flags & FLP_LOCATION_HAS_ACCURACY) { 443 jmethodID setAccuracy = sCallbackEnv->GetMethodID( 444 locationClass, 445 "setAccuracy", 446 "(F)V" 447 ); 448 sCallbackEnv->CallVoidMethod(locationObject, setAccuracy, location->accuracy); 449 } 450 451 // TODO: wire FlpLocation::sources_used when needed 452 453 sCallbackEnv->DeleteLocalRef(locationClass); 454} 455 456/* 457 * Helper function to serialize FlpLocation structures. 458 */ 459static void TranslateToObjectArray( 460 int32_t locationsCount, 461 FlpLocation** locations, 462 jobjectArray& locationsArray) { 463 jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME); 464 locationsArray = sCallbackEnv->NewObjectArray( 465 locationsCount, 466 locationClass, 467 /* initialElement */ NULL 468 ); 469 470 for (int i = 0; i < locationsCount; ++i) { 471 jobject locationObject = NULL; 472 TranslateToObject(locations[i], locationObject); 473 sCallbackEnv->SetObjectArrayElement(locationsArray, i, locationObject); 474 sCallbackEnv->DeleteLocalRef(locationObject); 475 } 476 477 sCallbackEnv->DeleteLocalRef(locationClass); 478} 479 480static void LocationCallback(int32_t locationsCount, FlpLocation** locations) { 481 if(!IsValidCallbackThread()) { 482 return; 483 } 484 485 if(locationsCount == 0 || locations == NULL) { 486 ALOGE( 487 "Invalid LocationCallback. Count: %d, Locations: %p", 488 locationsCount, 489 locations 490 ); 491 return; 492 } 493 494 jobjectArray locationsArray = NULL; 495 TranslateToObjectArray(locationsCount, locations, locationsArray); 496 497 sCallbackEnv->CallVoidMethod( 498 sCallbacksObj, 499 sOnLocationReport, 500 locationsArray 501 ); 502 CheckExceptions(sCallbackEnv, __FUNCTION__); 503 504 if(locationsArray != NULL) { 505 sCallbackEnv->DeleteLocalRef(locationsArray); 506 } 507} 508 509static void AcquireWakelock() { 510 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME); 511} 512 513static void ReleaseWakelock() { 514 release_wake_lock(WAKE_LOCK_NAME); 515} 516 517FlpCallbacks sFlpCallbacks = { 518 sizeof(FlpCallbacks), 519 LocationCallback, 520 AcquireWakelock, 521 ReleaseWakelock, 522 SetThreadEvent 523}; 524 525static void ReportData(char* data, int length) { 526 jstring stringData = NULL; 527 528 if(length != 0 && data != NULL) { 529 stringData = sCallbackEnv->NewString(reinterpret_cast<jchar*>(data), length); 530 } else { 531 ALOGE("Invalid ReportData callback. Length: %d, Data: %p", length, data); 532 return; 533 } 534 535 sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnDataReport, stringData); 536 CheckExceptions(sCallbackEnv, __FUNCTION__); 537} 538 539FlpDiagnosticCallbacks sFlpDiagnosticCallbacks = { 540 sizeof(FlpDiagnosticCallbacks), 541 SetThreadEvent, 542 ReportData 543}; 544 545static void GeofenceTransitionCallback( 546 int32_t geofenceId, 547 FlpLocation* location, 548 int32_t transition, 549 FlpUtcTime timestamp, 550 uint32_t sourcesUsed 551 ) { 552 if(!IsValidCallbackThread()) { 553 return; 554 } 555 556 if(location == NULL) { 557 ALOGE("GeofenceTransition received with invalid location: %p", location); 558 return; 559 } 560 561 jobject locationObject = NULL; 562 TranslateToObject(location, locationObject); 563 564 sCallbackEnv->CallVoidMethod( 565 sCallbacksObj, 566 sOnGeofenceTransition, 567 geofenceId, 568 locationObject, 569 transition, 570 timestamp, 571 sourcesUsed 572 ); 573 CheckExceptions(sCallbackEnv, __FUNCTION__); 574 575 if(locationObject != NULL) { 576 sCallbackEnv->DeleteLocalRef(locationObject); 577 } 578} 579 580static void GeofenceMonitorStatusCallback( 581 int32_t status, 582 uint32_t source, 583 FlpLocation* lastLocation) { 584 if(!IsValidCallbackThread()) { 585 return; 586 } 587 588 jobject locationObject = NULL; 589 if(lastLocation != NULL) { 590 TranslateToObject(lastLocation, locationObject); 591 } 592 593 sCallbackEnv->CallVoidMethod( 594 sCallbacksObj, 595 sOnGeofenceMonitorStatus, 596 status, 597 source, 598 locationObject 599 ); 600 CheckExceptions(sCallbackEnv, __FUNCTION__); 601 602 if(locationObject != NULL) { 603 sCallbackEnv->DeleteLocalRef(locationObject); 604 } 605} 606 607static void GeofenceAddCallback(int32_t geofenceId, int32_t result) { 608 if(!IsValidCallbackThread()) { 609 return; 610 } 611 612 sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnGeofenceAdd, geofenceId, result); 613 CheckExceptions(sCallbackEnv, __FUNCTION__); 614} 615 616static void GeofenceRemoveCallback(int32_t geofenceId, int32_t result) { 617 if(!IsValidCallbackThread()) { 618 return; 619 } 620 621 sCallbackEnv->CallVoidMethod( 622 sCallbacksObj, 623 sOnGeofenceRemove, 624 geofenceId, 625 result 626 ); 627 CheckExceptions(sCallbackEnv, __FUNCTION__); 628} 629 630static void GeofencePauseCallback(int32_t geofenceId, int32_t result) { 631 if(!IsValidCallbackThread()) { 632 return; 633 } 634 635 sCallbackEnv->CallVoidMethod( 636 sCallbacksObj, 637 sOnGeofencePause, 638 geofenceId, 639 result 640 ); 641 CheckExceptions(sCallbackEnv, __FUNCTION__); 642} 643 644static void GeofenceResumeCallback(int32_t geofenceId, int32_t result) { 645 if(!IsValidCallbackThread()) { 646 return; 647 } 648 649 sCallbackEnv->CallVoidMethod( 650 sCallbacksObj, 651 sOnGeofenceResume, 652 geofenceId, 653 result 654 ); 655 CheckExceptions(sCallbackEnv, __FUNCTION__); 656} 657 658FlpGeofenceCallbacks sFlpGeofenceCallbacks = { 659 sizeof(FlpGeofenceCallbacks), 660 GeofenceTransitionCallback, 661 GeofenceMonitorStatusCallback, 662 GeofenceAddCallback, 663 GeofenceRemoveCallback, 664 GeofencePauseCallback, 665 GeofenceResumeCallback, 666 SetThreadEvent 667}; 668 669/* 670 * Initializes the Fused Location Provider in the native side. It ensures that 671 * the Flp interfaces are initialized properly. 672 */ 673static void Init(JNIEnv* env, jobject obj) { 674 if(sCallbacksObj == NULL) { 675 sCallbacksObj = env->NewGlobalRef(obj); 676 } 677 678 // initialize the Flp interfaces 679 if(sFlpInterface == NULL || sFlpInterface->init(&sFlpCallbacks) != 0) { 680 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__); 681 } 682 683 if(sFlpDiagnosticInterface != NULL) { 684 sFlpDiagnosticInterface->init(&sFlpDiagnosticCallbacks); 685 } 686 687 if(sFlpGeofencingInterface != NULL) { 688 sFlpGeofencingInterface->init(&sFlpGeofenceCallbacks); 689 } 690 691 // TODO: inject any device context if when needed 692} 693 694static jboolean IsSupported(JNIEnv* env, jclass clazz) { 695 if (sFlpInterface == NULL) { 696 return JNI_FALSE; 697 } 698 return JNI_TRUE; 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 env->ReleaseIntArrayElements(geofenceIdsArray, geofenceIds, 0 /*mode*/); 941} 942 943static JNINativeMethod sMethods[] = { 944 //{"name", "signature", functionPointer } 945 {"nativeClassInit", "()V", reinterpret_cast<void*>(ClassInit)}, 946 {"nativeInit", "()V", reinterpret_cast<void*>(Init)}, 947 {"nativeCleanup", "()V", reinterpret_cast<void*>(Cleanup)}, 948 {"nativeIsSupported", "()Z", reinterpret_cast<void*>(IsSupported)}, 949 {"nativeGetBatchSize", "()I", reinterpret_cast<void*>(GetBatchSize)}, 950 {"nativeStartBatching", 951 "(ILandroid/location/FusedBatchOptions;)V", 952 reinterpret_cast<void*>(StartBatching)}, 953 {"nativeUpdateBatchingOptions", 954 "(ILandroid/location/FusedBatchOptions;)V", 955 reinterpret_cast<void*>(UpdateBatchingOptions)}, 956 {"nativeStopBatching", "(I)V", reinterpret_cast<void*>(StopBatching)}, 957 {"nativeRequestBatchedLocation", 958 "(I)V", 959 reinterpret_cast<void*>(GetBatchedLocation)}, 960 {"nativeInjectLocation", 961 "(Landroid/location/Location;)V", 962 reinterpret_cast<void*>(InjectLocation)}, 963 {"nativeIsDiagnosticSupported", 964 "()Z", 965 reinterpret_cast<void*>(IsDiagnosticSupported)}, 966 {"nativeInjectDiagnosticData", 967 "(Ljava/lang/String;)V", 968 reinterpret_cast<void*>(InjectDiagnosticData)}, 969 {"nativeIsDeviceContextSupported", 970 "()Z", 971 reinterpret_cast<void*>(IsDeviceContextSupported)}, 972 {"nativeInjectDeviceContext", 973 "(I)V", 974 reinterpret_cast<void*>(InjectDeviceContext)}, 975 {"nativeIsGeofencingSupported", 976 "()Z", 977 reinterpret_cast<void*>(IsGeofencingSupported)}, 978 {"nativeAddGeofences", 979 "([Landroid/hardware/location/GeofenceHardwareRequestParcelable;)V", 980 reinterpret_cast<void*>(AddGeofences)}, 981 {"nativePauseGeofence", "(I)V", reinterpret_cast<void*>(PauseGeofence)}, 982 {"nativeResumeGeofence", "(II)V", reinterpret_cast<void*>(ResumeGeofence)}, 983 {"nativeModifyGeofenceOption", 984 "(IIIIII)V", 985 reinterpret_cast<void*>(ModifyGeofenceOption)}, 986 {"nativeRemoveGeofences", "([I)V", reinterpret_cast<void*>(RemoveGeofences)} 987}; 988 989/* 990 * Registration method invoked on JNI Load. 991 */ 992int register_android_server_location_FlpHardwareProvider(JNIEnv* env) { 993 return jniRegisterNativeMethods( 994 env, 995 "com/android/server/location/FlpHardwareProvider", 996 sMethods, 997 NELEM(sMethods) 998 ); 999} 1000 1001} /* name-space Android */ 1002