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 
CheckExceptions(JNIEnv * env,const char * methodName)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 
ThrowOnError(JNIEnv * env,int resultCode,const char * methodName)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 
IsValidCallbackThreadEnvOnly()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 
IsValidCallbackThread()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 
BatchingCapabilitiesCallback(int32_t capabilities)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 
BatchingStatusCallback(int32_t status)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 
SetThreadEvent(ThreadEvent event)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  */
ClassInit(JNIEnv * env,jclass clazz)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  */
TranslateFromObject(JNIEnv * env,jobject locationObject,FlpLocation & location)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  */
TranslateFromObject(JNIEnv * env,jobject batchOptionsObject,FlpBatchOptions & batchOptions)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  */
TranslateGeofenceFromGeofenceHardwareRequestParcelable(JNIEnv * env,jobject geofenceRequestObject,Geofence & geofence)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  */
TranslateToObject(const FlpLocation * location,jobject & locationObject)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  */
TranslateToObjectArray(int32_t locationsCount,FlpLocation ** locations,jobjectArray & locationsArray)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 
LocationCallback(int32_t locationsCount,FlpLocation ** locations)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 
AcquireWakelock()592 static void AcquireWakelock() {
593   acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
594 }
595 
ReleaseWakelock()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 
ReportData(char * data,int length)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 
GeofenceTransitionCallback(int32_t geofenceId,FlpLocation * location,int32_t transition,FlpUtcTime timestamp,uint32_t sourcesUsed)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 
GeofenceMonitorStatusCallback(int32_t status,uint32_t source,FlpLocation * lastLocation)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 
GeofenceAddCallback(int32_t geofenceId,int32_t result)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 
GeofenceRemoveCallback(int32_t geofenceId,int32_t result)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 
GeofencePauseCallback(int32_t geofenceId,int32_t result)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 
GeofenceResumeCallback(int32_t geofenceId,int32_t result)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 
GeofencingCapabilitiesCallback(int32_t capabilities)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  */
Init(JNIEnv * env,jobject obj)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 
IsSupported(JNIEnv *,jclass)793 static jboolean IsSupported(JNIEnv* /* env */, jclass /* clazz */) {
794   if (sFlpInterface == NULL) {
795     return JNI_FALSE;
796   }
797   return JNI_TRUE;
798 }
799 
GetBatchSize(JNIEnv * env,jobject)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 
StartBatching(JNIEnv * env,jobject,jint id,jobject optionsObject)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 
UpdateBatchingOptions(JNIEnv * env,jobject,jint id,jobject optionsObject)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 
StopBatching(JNIEnv * env,jobject,jint id)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 
Cleanup(JNIEnv * env,jobject)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 
GetBatchedLocation(JNIEnv * env,jobject,jint lastNLocations)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 
FlushBatchedLocations(JNIEnv * env,jobject)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 
InjectLocation(JNIEnv * env,jobject,jobject locationObject)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 
IsDiagnosticSupported()895 static jboolean IsDiagnosticSupported() {
896   return sFlpDiagnosticInterface != NULL;
897 }
898 
InjectDiagnosticData(JNIEnv * env,jobject,jstring stringData)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 
IsDeviceContextSupported()919 static jboolean IsDeviceContextSupported() {
920   return sFlpDeviceContextInterface != NULL;
921 }
922 
InjectDeviceContext(JNIEnv * env,jobject,jint enabledMask)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 
IsGeofencingSupported()932 static jboolean IsGeofencingSupported() {
933   return sFlpGeofencingInterface != NULL;
934 }
935 
AddGeofences(JNIEnv * env,jobject,jobjectArray geofenceRequestsArray)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 
PauseGeofence(JNIEnv * env,jobject,jint geofenceId)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 
ResumeGeofence(JNIEnv * env,jobject,jint geofenceId,jint monitorTransitions)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 
ModifyGeofenceOption(JNIEnv * env,jobject,jint geofenceId,jint lastTransition,jint monitorTransitions,jint notificationResponsiveness,jint unknownTimer,jint sourcesToUse)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 
RemoveGeofences(JNIEnv * env,jobject,jintArray geofenceIdsArray)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  */
register_android_server_location_FlpHardwareProvider(JNIEnv * env)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