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