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