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