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