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