blob: 774577d43d69d39a079d7054043c9cfda81dd40d [file] [log] [blame]
destradaa1af4b022013-07-12 15:43:36 -07001/*
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
destradaa264705a2013-08-21 12:55:32 -070017#define LOG_TAG "FlpHardwareProvider"
destradaa1af4b022013-07-12 15:43:36 -070018#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"
Ruben Brunk87eac992013-09-09 17:44:59 -070026#include "android_runtime/Log.h"
destradaa1af4b022013-07-12 15:43:36 -070027#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
David Christiecfc9b6d2015-04-14 12:14:03 -070034static jmethodID sSetVersion = NULL;
destradaa1af4b022013-07-12 15:43:36 -070035static jmethodID sOnLocationReport = NULL;
36static jmethodID sOnDataReport = NULL;
David Christieffca45a2015-04-11 23:15:08 -070037static jmethodID sOnBatchingCapabilities = NULL;
David Christie15003f12015-04-12 20:57:57 -070038static jmethodID sOnBatchingStatus = NULL;
destradaa1af4b022013-07-12 15:43:36 -070039static jmethodID sOnGeofenceTransition = NULL;
40static jmethodID sOnGeofenceMonitorStatus = NULL;
41static jmethodID sOnGeofenceAdd = NULL;
42static jmethodID sOnGeofenceRemove = NULL;
43static jmethodID sOnGeofencePause = NULL;
44static jmethodID sOnGeofenceResume = NULL;
David Christieffca45a2015-04-11 23:15:08 -070045static jmethodID sOnGeofencingCapabilities = NULL;
destradaa1af4b022013-07-12 15:43:36 -070046
47static const FlpLocationInterface* sFlpInterface = NULL;
48static const FlpDiagnosticInterface* sFlpDiagnosticInterface = NULL;
49static const FlpGeofencingInterface* sFlpGeofencingInterface = NULL;
50static const FlpDeviceContextInterface* sFlpDeviceContextInterface = NULL;
51
52namespace android {
53
54static 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
64static 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);
destradaaff8e6092014-08-12 19:04:03 -070073 // 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);
destradaa1af4b022013-07-12 15:43:36 -070079}
80
81static bool IsValidCallbackThread() {
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
David Christieffca45a2015-04-11 23:15:08 -070092static void BatchingCapabilitiesCallback(int32_t capabilities) {
93 if(!IsValidCallbackThread()) {
94 return;
95 }
96
97 sCallbackEnv->CallVoidMethod(
98 sCallbacksObj,
99 sOnBatchingCapabilities,
100 capabilities
101 );
102 CheckExceptions(sCallbackEnv, __FUNCTION__);
103}
104
David Christie15003f12015-04-12 20:57:57 -0700105static void BatchingStatusCallback(int32_t status) {
106 if(!IsValidCallbackThread()) {
107 return;
108 }
109
110 sCallbackEnv->CallVoidMethod(
111 sCallbacksObj,
112 sOnBatchingStatus,
113 status
114 );
115 CheckExceptions(sCallbackEnv, __FUNCTION__);
116}
117
destradaa1af4b022013-07-12 15:43:36 -0700118static int SetThreadEvent(ThreadEvent event) {
119 JavaVM* javaVm = AndroidRuntime::getJavaVM();
120
121 switch(event) {
122 case ASSOCIATE_JVM:
123 {
124 if(sCallbackEnv != NULL) {
125 ALOGE(
126 "Attempted to associate callback in '%s'. Callback already associated.",
127 __FUNCTION__
128 );
129 return FLP_RESULT_ERROR;
130 }
131
132 JavaVMAttachArgs args = {
133 JNI_VERSION_1_6,
134 "FLP Service Callback Thread",
135 /* group */ NULL
136 };
137
138 jint attachResult = javaVm->AttachCurrentThread(&sCallbackEnv, &args);
139 if (attachResult != 0) {
140 ALOGE("Callback thread attachment error: %d", attachResult);
141 return FLP_RESULT_ERROR;
142 }
143
144 ALOGV("Callback thread attached: %p", sCallbackEnv);
David Christiecfc9b6d2015-04-14 12:14:03 -0700145
146 // Send the version to the upper layer.
147 sCallbackEnv->CallVoidMethod(
148 sCallbacksObj,
149 sSetVersion,
150 sFlpInterface->size == sizeof(FlpLocationInterface) ? 2 : 1
151 );
152 CheckExceptions(sCallbackEnv, __FUNCTION__);
destradaa1af4b022013-07-12 15:43:36 -0700153 break;
154 }
155 case DISASSOCIATE_JVM:
156 {
157 if (!IsValidCallbackThread()) {
158 ALOGE(
159 "Attempted to dissasociate an unnownk callback thread : '%s'.",
160 __FUNCTION__
161 );
162 return FLP_RESULT_ERROR;
163 }
164
165 if (javaVm->DetachCurrentThread() != 0) {
166 return FLP_RESULT_ERROR;
167 }
168
169 sCallbackEnv = NULL;
170 break;
171 }
172 default:
173 ALOGE("Invalid ThreadEvent request %d", event);
174 return FLP_RESULT_ERROR;
175 }
176
177 return FLP_RESULT_SUCCESS;
178}
179
180/*
181 * Initializes the FlpHardwareProvider class from the native side by opening
182 * the HW module and obtaining the proper interfaces.
183 */
184static void ClassInit(JNIEnv* env, jclass clazz) {
destradaa5ce66d82014-05-28 18:24:08 -0700185 sFlpInterface = NULL;
186
destradaa1af4b022013-07-12 15:43:36 -0700187 // get references to the Java provider methods
David Christiecfc9b6d2015-04-14 12:14:03 -0700188 sSetVersion = env->GetMethodID(
189 clazz,
190 "setVersion",
191 "(I)V");
destradaa1af4b022013-07-12 15:43:36 -0700192 sOnLocationReport = env->GetMethodID(
193 clazz,
194 "onLocationReport",
195 "([Landroid/location/Location;)V");
196 sOnDataReport = env->GetMethodID(
197 clazz,
198 "onDataReport",
199 "(Ljava/lang/String;)V"
200 );
David Christieffca45a2015-04-11 23:15:08 -0700201 sOnBatchingCapabilities = env->GetMethodID(
202 clazz,
203 "onBatchingCapabilities",
204 "(I)V");
David Christie15003f12015-04-12 20:57:57 -0700205 sOnBatchingStatus = env->GetMethodID(
206 clazz,
207 "onBatchingStatus",
208 "(I)V");
David Christieffca45a2015-04-11 23:15:08 -0700209 sOnGeofencingCapabilities = env->GetMethodID(
210 clazz,
211 "onGeofencingCapabilities",
212 "(I)V");
destradaa1af4b022013-07-12 15:43:36 -0700213 sOnGeofenceTransition = env->GetMethodID(
214 clazz,
215 "onGeofenceTransition",
216 "(ILandroid/location/Location;IJI)V"
217 );
218 sOnGeofenceMonitorStatus = env->GetMethodID(
219 clazz,
220 "onGeofenceMonitorStatus",
221 "(IILandroid/location/Location;)V"
222 );
223 sOnGeofenceAdd = env->GetMethodID(clazz, "onGeofenceAdd", "(II)V");
224 sOnGeofenceRemove = env->GetMethodID(clazz, "onGeofenceRemove", "(II)V");
225 sOnGeofencePause = env->GetMethodID(clazz, "onGeofencePause", "(II)V");
226 sOnGeofenceResume = env->GetMethodID(clazz, "onGeofenceResume", "(II)V");
destradaa5ce66d82014-05-28 18:24:08 -0700227
228 // open the hardware module
229 const hw_module_t* module = NULL;
230 int err = hw_get_module(FUSED_LOCATION_HARDWARE_MODULE_ID, &module);
231 if (err != 0) {
232 ALOGE("Error hw_get_module '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err);
233 return;
234 }
235
236 err = module->methods->open(
237 module,
238 FUSED_LOCATION_HARDWARE_MODULE_ID,
239 &sHardwareDevice);
240 if (err != 0) {
241 ALOGE("Error opening device '%s': %d", FUSED_LOCATION_HARDWARE_MODULE_ID, err);
242 return;
243 }
244
245 // acquire the interfaces pointers
246 flp_device_t* flp_device = reinterpret_cast<flp_device_t*>(sHardwareDevice);
247 sFlpInterface = flp_device->get_flp_interface(flp_device);
248
249 if (sFlpInterface != NULL) {
250 sFlpDiagnosticInterface = reinterpret_cast<const FlpDiagnosticInterface*>(
251 sFlpInterface->get_extension(FLP_DIAGNOSTIC_INTERFACE));
252
253 sFlpGeofencingInterface = reinterpret_cast<const FlpGeofencingInterface*>(
254 sFlpInterface->get_extension(FLP_GEOFENCING_INTERFACE));
255
256 sFlpDeviceContextInterface = reinterpret_cast<const FlpDeviceContextInterface*>(
257 sFlpInterface->get_extension(FLP_DEVICE_CONTEXT_INTERFACE));
258 }
destradaa1af4b022013-07-12 15:43:36 -0700259}
260
261/*
262 * Helper function to unwrap a java object back into a FlpLocation structure.
263 */
264static void TranslateFromObject(
265 JNIEnv* env,
266 jobject locationObject,
267 FlpLocation& location) {
268 location.size = sizeof(FlpLocation);
269 location.flags = 0;
270
271 jclass locationClass = env->GetObjectClass(locationObject);
272
273 jmethodID getLatitude = env->GetMethodID(locationClass, "getLatitude", "()D");
274 location.latitude = env->CallDoubleMethod(locationObject, getLatitude);
275 jmethodID getLongitude = env->GetMethodID(locationClass, "getLongitude", "()D");
276 location.longitude = env->CallDoubleMethod(locationObject, getLongitude);
277 jmethodID getTime = env->GetMethodID(locationClass, "getTime", "()J");
278 location.timestamp = env->CallLongMethod(locationObject, getTime);
279 location.flags |= FLP_LOCATION_HAS_LAT_LONG;
280
281 jmethodID hasAltitude = env->GetMethodID(locationClass, "hasAltitude", "()Z");
282 if (env->CallBooleanMethod(locationObject, hasAltitude)) {
283 jmethodID getAltitude = env->GetMethodID(locationClass, "getAltitude", "()D");
284 location.altitude = env->CallDoubleMethod(locationObject, getAltitude);
285 location.flags |= FLP_LOCATION_HAS_ALTITUDE;
286 }
287
288 jmethodID hasSpeed = env->GetMethodID(locationClass, "hasSpeed", "()Z");
289 if (env->CallBooleanMethod(locationObject, hasSpeed)) {
290 jmethodID getSpeed = env->GetMethodID(locationClass, "getSpeed", "()F");
291 location.speed = env->CallFloatMethod(locationObject, getSpeed);
292 location.flags |= FLP_LOCATION_HAS_SPEED;
293 }
294
295 jmethodID hasBearing = env->GetMethodID(locationClass, "hasBearing", "()Z");
296 if (env->CallBooleanMethod(locationObject, hasBearing)) {
297 jmethodID getBearing = env->GetMethodID(locationClass, "getBearing", "()F");
298 location.bearing = env->CallFloatMethod(locationObject, getBearing);
299 location.flags |= FLP_LOCATION_HAS_BEARING;
300 }
301
302 jmethodID hasAccuracy = env->GetMethodID(locationClass, "hasAccuracy", "()Z");
303 if (env->CallBooleanMethod(locationObject, hasAccuracy)) {
304 jmethodID getAccuracy = env->GetMethodID(
305 locationClass,
306 "getAccuracy",
307 "()F"
308 );
309 location.accuracy = env->CallFloatMethod(locationObject, getAccuracy);
310 location.flags |= FLP_LOCATION_HAS_ACCURACY;
311 }
312
313 // TODO: wire sources_used if Location class exposes them
destradaab75cb3a2013-08-23 17:26:16 -0700314
315 env->DeleteLocalRef(locationClass);
destradaa1af4b022013-07-12 15:43:36 -0700316}
317
318/*
319 * Helper function to unwrap FlpBatchOptions from the Java Runtime calls.
320 */
321static void TranslateFromObject(
322 JNIEnv* env,
323 jobject batchOptionsObject,
324 FlpBatchOptions& batchOptions) {
325 jclass batchOptionsClass = env->GetObjectClass(batchOptionsObject);
326
327 jmethodID getMaxPower = env->GetMethodID(
328 batchOptionsClass,
329 "getMaxPowerAllocationInMW",
330 "()D"
331 );
332 batchOptions.max_power_allocation_mW = env->CallDoubleMethod(
333 batchOptionsObject,
334 getMaxPower
335 );
336
337 jmethodID getPeriod = env->GetMethodID(
338 batchOptionsClass,
339 "getPeriodInNS",
340 "()J"
341 );
342 batchOptions.period_ns = env->CallLongMethod(batchOptionsObject, getPeriod);
343
344 jmethodID getSourcesToUse = env->GetMethodID(
345 batchOptionsClass,
346 "getSourcesToUse",
347 "()I"
348 );
349 batchOptions.sources_to_use = env->CallIntMethod(
350 batchOptionsObject,
351 getSourcesToUse
352 );
353
David Christie295a93b2015-04-08 15:31:30 -0700354 jmethodID getSmallestDisplacementMeters = env->GetMethodID(
355 batchOptionsClass,
356 "getSmallestDisplacementMeters",
357 "()F"
358 );
359 batchOptions.smallest_displacement_meters
360 = env->CallFloatMethod(batchOptionsObject, getSmallestDisplacementMeters);
361
destradaa1af4b022013-07-12 15:43:36 -0700362 jmethodID getFlags = env->GetMethodID(batchOptionsClass, "getFlags", "()I");
363 batchOptions.flags = env->CallIntMethod(batchOptionsObject, getFlags);
destradaab75cb3a2013-08-23 17:26:16 -0700364
365 env->DeleteLocalRef(batchOptionsClass);
destradaa1af4b022013-07-12 15:43:36 -0700366}
367
368/*
destradaa0682809a2013-08-12 18:50:30 -0700369 * Helper function to unwrap Geofence structures from the Java Runtime calls.
370 */
371static void TranslateGeofenceFromGeofenceHardwareRequestParcelable(
372 JNIEnv* env,
373 jobject geofenceRequestObject,
374 Geofence& geofence) {
375 jclass geofenceRequestClass = env->GetObjectClass(geofenceRequestObject);
376
377 jmethodID getId = env->GetMethodID(geofenceRequestClass, "getId", "()I");
378 geofence.geofence_id = env->CallIntMethod(geofenceRequestObject, getId);
379
380 jmethodID getType = env->GetMethodID(geofenceRequestClass, "getType", "()I");
381 // this works because GeofenceHardwareRequest.java and fused_location.h have
382 // the same notion of geofence types
383 GeofenceType type = (GeofenceType)env->CallIntMethod(geofenceRequestObject, getType);
384 if(type != TYPE_CIRCLE) {
385 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
386 }
387 geofence.data->type = type;
388 GeofenceCircle& circle = geofence.data->geofence.circle;
389
390 jmethodID getLatitude = env->GetMethodID(
391 geofenceRequestClass,
392 "getLatitude",
393 "()D");
394 circle.latitude = env->CallDoubleMethod(geofenceRequestObject, getLatitude);
395
396 jmethodID getLongitude = env->GetMethodID(
397 geofenceRequestClass,
398 "getLongitude",
399 "()D");
400 circle.longitude = env->CallDoubleMethod(geofenceRequestObject, getLongitude);
401
402 jmethodID getRadius = env->GetMethodID(geofenceRequestClass, "getRadius", "()D");
403 circle.radius_m = env->CallDoubleMethod(geofenceRequestObject, getRadius);
404
405 GeofenceOptions* options = geofence.options;
406 jmethodID getMonitorTransitions = env->GetMethodID(
407 geofenceRequestClass,
408 "getMonitorTransitions",
409 "()I");
410 options->monitor_transitions = env->CallIntMethod(
411 geofenceRequestObject,
412 getMonitorTransitions);
413
414 jmethodID getUnknownTimer = env->GetMethodID(
415 geofenceRequestClass,
416 "getUnknownTimer",
417 "()I");
418 options->unknown_timer_ms = env->CallIntMethod(geofenceRequestObject, getUnknownTimer);
419
420 jmethodID getNotificationResponsiveness = env->GetMethodID(
421 geofenceRequestClass,
422 "getNotificationResponsiveness",
destradaa839904e2013-09-11 12:42:51 -0700423 "()I");
destradaa0682809a2013-08-12 18:50:30 -0700424 options->notification_responsivenes_ms = env->CallIntMethod(
425 geofenceRequestObject,
426 getNotificationResponsiveness);
427
428 jmethodID getLastTransition = env->GetMethodID(
429 geofenceRequestClass,
430 "getLastTransition",
431 "()I");
432 options->last_transition = env->CallIntMethod(geofenceRequestObject, getLastTransition);
433
destradaaf9a274c2014-07-25 15:11:56 -0700434 jmethodID getSourceTechnologies =
435 env->GetMethodID(geofenceRequestClass, "getSourceTechnologies", "()I");
436 options->sources_to_use = env->CallIntMethod(geofenceRequestObject, getSourceTechnologies);
destradaab75cb3a2013-08-23 17:26:16 -0700437
438 env->DeleteLocalRef(geofenceRequestClass);
destradaa0682809a2013-08-12 18:50:30 -0700439}
440
441/*
destradaa1af4b022013-07-12 15:43:36 -0700442 * Helper function to transform FlpLocation into a java object.
443 */
444static void TranslateToObject(const FlpLocation* location, jobject& locationObject) {
445 jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME);
446 jmethodID locationCtor = sCallbackEnv->GetMethodID(
447 locationClass,
448 "<init>",
449 "(Ljava/lang/String;)V"
450 );
451
452 // the provider is set in the upper JVM layer
453 locationObject = sCallbackEnv->NewObject(locationClass, locationCtor, NULL);
454 jint flags = location->flags;
455
456 // set the valid information in the object
457 if (flags & FLP_LOCATION_HAS_LAT_LONG) {
458 jmethodID setLatitude = sCallbackEnv->GetMethodID(
459 locationClass,
460 "setLatitude",
461 "(D)V"
462 );
463 sCallbackEnv->CallVoidMethod(locationObject, setLatitude, location->latitude);
464
465 jmethodID setLongitude = sCallbackEnv->GetMethodID(
466 locationClass,
467 "setLongitude",
468 "(D)V"
469 );
470 sCallbackEnv->CallVoidMethod(
471 locationObject,
472 setLongitude,
473 location->longitude
474 );
475
476 jmethodID setTime = sCallbackEnv->GetMethodID(
477 locationClass,
478 "setTime",
479 "(J)V"
480 );
481 sCallbackEnv->CallVoidMethod(locationObject, setTime, location->timestamp);
482 }
483
484 if (flags & FLP_LOCATION_HAS_ALTITUDE) {
485 jmethodID setAltitude = sCallbackEnv->GetMethodID(
486 locationClass,
487 "setAltitude",
488 "(D)V"
489 );
490 sCallbackEnv->CallVoidMethod(locationObject, setAltitude, location->altitude);
491 }
492
493 if (flags & FLP_LOCATION_HAS_SPEED) {
494 jmethodID setSpeed = sCallbackEnv->GetMethodID(
495 locationClass,
496 "setSpeed",
497 "(F)V"
498 );
499 sCallbackEnv->CallVoidMethod(locationObject, setSpeed, location->speed);
500 }
501
502 if (flags & FLP_LOCATION_HAS_BEARING) {
503 jmethodID setBearing = sCallbackEnv->GetMethodID(
504 locationClass,
505 "setBearing",
506 "(F)V"
507 );
508 sCallbackEnv->CallVoidMethod(locationObject, setBearing, location->bearing);
509 }
510
511 if (flags & FLP_LOCATION_HAS_ACCURACY) {
512 jmethodID setAccuracy = sCallbackEnv->GetMethodID(
513 locationClass,
514 "setAccuracy",
515 "(F)V"
516 );
517 sCallbackEnv->CallVoidMethod(locationObject, setAccuracy, location->accuracy);
518 }
519
520 // TODO: wire FlpLocation::sources_used when needed
destradaab75cb3a2013-08-23 17:26:16 -0700521
522 sCallbackEnv->DeleteLocalRef(locationClass);
destradaa1af4b022013-07-12 15:43:36 -0700523}
524
525/*
526 * Helper function to serialize FlpLocation structures.
527 */
528static void TranslateToObjectArray(
529 int32_t locationsCount,
530 FlpLocation** locations,
531 jobjectArray& locationsArray) {
532 jclass locationClass = sCallbackEnv->FindClass(LOCATION_CLASS_NAME);
533 locationsArray = sCallbackEnv->NewObjectArray(
534 locationsCount,
535 locationClass,
536 /* initialElement */ NULL
537 );
538
539 for (int i = 0; i < locationsCount; ++i) {
540 jobject locationObject = NULL;
541 TranslateToObject(locations[i], locationObject);
542 sCallbackEnv->SetObjectArrayElement(locationsArray, i, locationObject);
543 sCallbackEnv->DeleteLocalRef(locationObject);
544 }
destradaab75cb3a2013-08-23 17:26:16 -0700545
546 sCallbackEnv->DeleteLocalRef(locationClass);
destradaa1af4b022013-07-12 15:43:36 -0700547}
548
549static void LocationCallback(int32_t locationsCount, FlpLocation** locations) {
550 if(!IsValidCallbackThread()) {
551 return;
552 }
553
554 if(locationsCount == 0 || locations == NULL) {
555 ALOGE(
556 "Invalid LocationCallback. Count: %d, Locations: %p",
557 locationsCount,
558 locations
559 );
560 return;
561 }
562
563 jobjectArray locationsArray = NULL;
564 TranslateToObjectArray(locationsCount, locations, locationsArray);
565
566 sCallbackEnv->CallVoidMethod(
567 sCallbacksObj,
568 sOnLocationReport,
569 locationsArray
570 );
571 CheckExceptions(sCallbackEnv, __FUNCTION__);
destradaab75cb3a2013-08-23 17:26:16 -0700572
573 if(locationsArray != NULL) {
574 sCallbackEnv->DeleteLocalRef(locationsArray);
575 }
destradaa1af4b022013-07-12 15:43:36 -0700576}
577
578static void AcquireWakelock() {
579 acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
580}
581
582static void ReleaseWakelock() {
583 release_wake_lock(WAKE_LOCK_NAME);
584}
585
586FlpCallbacks sFlpCallbacks = {
587 sizeof(FlpCallbacks),
588 LocationCallback,
589 AcquireWakelock,
590 ReleaseWakelock,
David Christieffca45a2015-04-11 23:15:08 -0700591 SetThreadEvent,
David Christie15003f12015-04-12 20:57:57 -0700592 BatchingCapabilitiesCallback,
593 BatchingStatusCallback
destradaa1af4b022013-07-12 15:43:36 -0700594};
595
596static void ReportData(char* data, int length) {
597 jstring stringData = NULL;
598
599 if(length != 0 && data != NULL) {
600 stringData = sCallbackEnv->NewString(reinterpret_cast<jchar*>(data), length);
601 } else {
602 ALOGE("Invalid ReportData callback. Length: %d, Data: %p", length, data);
603 return;
604 }
605
606 sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnDataReport, stringData);
607 CheckExceptions(sCallbackEnv, __FUNCTION__);
608}
609
610FlpDiagnosticCallbacks sFlpDiagnosticCallbacks = {
611 sizeof(FlpDiagnosticCallbacks),
612 SetThreadEvent,
613 ReportData
614};
615
616static void GeofenceTransitionCallback(
617 int32_t geofenceId,
618 FlpLocation* location,
619 int32_t transition,
620 FlpUtcTime timestamp,
621 uint32_t sourcesUsed
622 ) {
623 if(!IsValidCallbackThread()) {
624 return;
625 }
626
627 if(location == NULL) {
628 ALOGE("GeofenceTransition received with invalid location: %p", location);
629 return;
630 }
631
632 jobject locationObject = NULL;
633 TranslateToObject(location, locationObject);
634
635 sCallbackEnv->CallVoidMethod(
636 sCallbacksObj,
637 sOnGeofenceTransition,
638 geofenceId,
639 locationObject,
640 transition,
641 timestamp,
642 sourcesUsed
643 );
644 CheckExceptions(sCallbackEnv, __FUNCTION__);
destradaab75cb3a2013-08-23 17:26:16 -0700645
646 if(locationObject != NULL) {
647 sCallbackEnv->DeleteLocalRef(locationObject);
648 }
destradaa1af4b022013-07-12 15:43:36 -0700649}
650
651static void GeofenceMonitorStatusCallback(
652 int32_t status,
653 uint32_t source,
654 FlpLocation* lastLocation) {
655 if(!IsValidCallbackThread()) {
656 return;
657 }
658
659 jobject locationObject = NULL;
660 if(lastLocation != NULL) {
661 TranslateToObject(lastLocation, locationObject);
662 }
663
664 sCallbackEnv->CallVoidMethod(
665 sCallbacksObj,
666 sOnGeofenceMonitorStatus,
667 status,
668 source,
669 locationObject
670 );
671 CheckExceptions(sCallbackEnv, __FUNCTION__);
destradaab75cb3a2013-08-23 17:26:16 -0700672
673 if(locationObject != NULL) {
674 sCallbackEnv->DeleteLocalRef(locationObject);
675 }
destradaa1af4b022013-07-12 15:43:36 -0700676}
677
678static void GeofenceAddCallback(int32_t geofenceId, int32_t result) {
679 if(!IsValidCallbackThread()) {
680 return;
681 }
682
683 sCallbackEnv->CallVoidMethod(sCallbacksObj, sOnGeofenceAdd, geofenceId, result);
684 CheckExceptions(sCallbackEnv, __FUNCTION__);
685}
686
687static void GeofenceRemoveCallback(int32_t geofenceId, int32_t result) {
688 if(!IsValidCallbackThread()) {
689 return;
690 }
691
692 sCallbackEnv->CallVoidMethod(
693 sCallbacksObj,
694 sOnGeofenceRemove,
695 geofenceId,
696 result
697 );
698 CheckExceptions(sCallbackEnv, __FUNCTION__);
699}
700
701static void GeofencePauseCallback(int32_t geofenceId, int32_t result) {
702 if(!IsValidCallbackThread()) {
703 return;
704 }
705
706 sCallbackEnv->CallVoidMethod(
707 sCallbacksObj,
708 sOnGeofencePause,
709 geofenceId,
710 result
711 );
712 CheckExceptions(sCallbackEnv, __FUNCTION__);
713}
714
715static void GeofenceResumeCallback(int32_t geofenceId, int32_t result) {
716 if(!IsValidCallbackThread()) {
717 return;
718 }
719
720 sCallbackEnv->CallVoidMethod(
721 sCallbacksObj,
722 sOnGeofenceResume,
723 geofenceId,
724 result
725 );
726 CheckExceptions(sCallbackEnv, __FUNCTION__);
727}
728
David Christieffca45a2015-04-11 23:15:08 -0700729static void GeofencingCapabilitiesCallback(int32_t capabilities) {
730 if(!IsValidCallbackThread()) {
731 return;
732 }
733
734 sCallbackEnv->CallVoidMethod(
735 sCallbacksObj,
736 sOnGeofencingCapabilities,
737 capabilities
738 );
739 CheckExceptions(sCallbackEnv, __FUNCTION__);
740}
741
destradaa1af4b022013-07-12 15:43:36 -0700742FlpGeofenceCallbacks sFlpGeofenceCallbacks = {
743 sizeof(FlpGeofenceCallbacks),
744 GeofenceTransitionCallback,
745 GeofenceMonitorStatusCallback,
746 GeofenceAddCallback,
747 GeofenceRemoveCallback,
748 GeofencePauseCallback,
749 GeofenceResumeCallback,
David Christieffca45a2015-04-11 23:15:08 -0700750 SetThreadEvent,
751 GeofencingCapabilitiesCallback
destradaa1af4b022013-07-12 15:43:36 -0700752};
753
754/*
755 * Initializes the Fused Location Provider in the native side. It ensures that
756 * the Flp interfaces are initialized properly.
757 */
758static void Init(JNIEnv* env, jobject obj) {
destradaa1af4b022013-07-12 15:43:36 -0700759 if(sCallbacksObj == NULL) {
760 sCallbacksObj = env->NewGlobalRef(obj);
761 }
762
763 // initialize the Flp interfaces
764 if(sFlpInterface == NULL || sFlpInterface->init(&sFlpCallbacks) != 0) {
765 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
766 }
767
768 if(sFlpDiagnosticInterface != NULL) {
769 sFlpDiagnosticInterface->init(&sFlpDiagnosticCallbacks);
770 }
771
772 if(sFlpGeofencingInterface != NULL) {
773 sFlpGeofencingInterface->init(&sFlpGeofenceCallbacks);
774 }
775
776 // TODO: inject any device context if when needed
777}
778
Andreas Gampe184e3ed2014-09-29 15:04:06 -0700779static jboolean IsSupported(JNIEnv* /* env */, jclass /* clazz */) {
destradaa5ce66d82014-05-28 18:24:08 -0700780 if (sFlpInterface == NULL) {
781 return JNI_FALSE;
782 }
783 return JNI_TRUE;
destradaa1af4b022013-07-12 15:43:36 -0700784}
785
Andreas Gampe184e3ed2014-09-29 15:04:06 -0700786static jint GetBatchSize(JNIEnv* env, jobject /* object */) {
destradaa1af4b022013-07-12 15:43:36 -0700787 if(sFlpInterface == NULL) {
788 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
789 }
790
791 return sFlpInterface->get_batch_size();
792}
793
794static void StartBatching(
795 JNIEnv* env,
Andreas Gampe184e3ed2014-09-29 15:04:06 -0700796 jobject /* object */,
destradaa1af4b022013-07-12 15:43:36 -0700797 jint id,
798 jobject optionsObject) {
799 if(sFlpInterface == NULL || optionsObject == NULL) {
800 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
801 }
802
803 FlpBatchOptions options;
804 TranslateFromObject(env, optionsObject, options);
805 int result = sFlpInterface->start_batching(id, &options);
806 ThrowOnError(env, result, __FUNCTION__);
807}
808
809static void UpdateBatchingOptions(
810 JNIEnv* env,
Andreas Gampe184e3ed2014-09-29 15:04:06 -0700811 jobject /* object */,
destradaa1af4b022013-07-12 15:43:36 -0700812 jint id,
813 jobject optionsObject) {
814 if(sFlpInterface == NULL || optionsObject == NULL) {
815 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
816 }
817
818 FlpBatchOptions options;
819 TranslateFromObject(env, optionsObject, options);
820 int result = sFlpInterface->update_batching_options(id, &options);
821 ThrowOnError(env, result, __FUNCTION__);
822}
823
Andreas Gampe184e3ed2014-09-29 15:04:06 -0700824static void StopBatching(JNIEnv* env, jobject /* object */, jint id) {
destradaa1af4b022013-07-12 15:43:36 -0700825 if(sFlpInterface == NULL) {
826 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
827 }
828
829 sFlpInterface->stop_batching(id);
830}
831
Andreas Gampe184e3ed2014-09-29 15:04:06 -0700832static void Cleanup(JNIEnv* env, jobject /* object */) {
destradaa1af4b022013-07-12 15:43:36 -0700833 if(sFlpInterface == NULL) {
834 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
835 }
836
837 sFlpInterface->cleanup();
838
839 if(sCallbacksObj != NULL) {
840 env->DeleteGlobalRef(sCallbacksObj);
841 sCallbacksObj = NULL;
842 }
destradaa1af4b022013-07-12 15:43:36 -0700843}
844
Andreas Gampe184e3ed2014-09-29 15:04:06 -0700845static void GetBatchedLocation(JNIEnv* env, jobject /* object */, jint lastNLocations) {
destradaa1af4b022013-07-12 15:43:36 -0700846 if(sFlpInterface == NULL) {
847 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
848 }
849
850 sFlpInterface->get_batched_location(lastNLocations);
851}
852
David Christiefff30432015-04-12 21:26:02 -0700853static void FlushBatchedLocations(JNIEnv* env, jobject /* object */) {
854 if(sFlpInterface == NULL) {
855 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
856 }
857
858 sFlpInterface->flush_batched_locations();
859}
860
Andreas Gampe184e3ed2014-09-29 15:04:06 -0700861static void InjectLocation(JNIEnv* env, jobject /* object */, jobject locationObject) {
destradaa1af4b022013-07-12 15:43:36 -0700862 if(locationObject == NULL) {
863 ALOGE("Invalid location for injection: %p", locationObject);
864 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
865 }
866
867 if(sFlpInterface == NULL) {
868 // there is no listener, bail
869 return;
870 }
871
872 FlpLocation location;
873 TranslateFromObject(env, locationObject, location);
874 int result = sFlpInterface->inject_location(&location);
destradaa264705a2013-08-21 12:55:32 -0700875 if (result != FLP_RESULT_SUCCESS) {
destradaa1af4b022013-07-12 15:43:36 -0700876 // do not throw but log, this operation should be fire and forget
877 ALOGE("Error %d in '%s'", result, __FUNCTION__);
878 }
879}
880
881static jboolean IsDiagnosticSupported() {
882 return sFlpDiagnosticInterface != NULL;
883}
884
Andreas Gampe184e3ed2014-09-29 15:04:06 -0700885static void InjectDiagnosticData(JNIEnv* env, jobject /* object */, jstring stringData) {
destradaa1af4b022013-07-12 15:43:36 -0700886 if(stringData == NULL) {
887 ALOGE("Invalid diagnostic data for injection: %p", stringData);
888 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
889 }
890
891 if(sFlpDiagnosticInterface == NULL) {
892 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
893 }
894
895 int length = env->GetStringLength(stringData);
896 const jchar* data = env->GetStringChars(stringData, /* isCopy */ NULL);
897 if(data == NULL) {
898 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
899 }
900
901 int result = sFlpDiagnosticInterface->inject_data((char*) data, length);
902 ThrowOnError(env, result, __FUNCTION__);
903}
904
905static jboolean IsDeviceContextSupported() {
906 return sFlpDeviceContextInterface != NULL;
907}
908
Andreas Gampe184e3ed2014-09-29 15:04:06 -0700909static void InjectDeviceContext(JNIEnv* env, jobject /* object */, jint enabledMask) {
destradaa1af4b022013-07-12 15:43:36 -0700910 if(sFlpDeviceContextInterface == NULL) {
911 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
912 }
913
914 int result = sFlpDeviceContextInterface->inject_device_context(enabledMask);
915 ThrowOnError(env, result, __FUNCTION__);
916}
917
918static jboolean IsGeofencingSupported() {
919 return sFlpGeofencingInterface != NULL;
920}
921
922static void AddGeofences(
923 JNIEnv* env,
Andreas Gampe184e3ed2014-09-29 15:04:06 -0700924 jobject /* object */,
destradaa0682809a2013-08-12 18:50:30 -0700925 jobjectArray geofenceRequestsArray) {
926 if(geofenceRequestsArray == NULL) {
927 ALOGE("Invalid Geofences to add: %p", geofenceRequestsArray);
destradaa1af4b022013-07-12 15:43:36 -0700928 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
929 }
930
931 if (sFlpGeofencingInterface == NULL) {
932 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
933 }
934
destradaa0682809a2013-08-12 18:50:30 -0700935 jint geofenceRequestsCount = env->GetArrayLength(geofenceRequestsArray);
936 if(geofenceRequestsCount == 0) {
937 return;
938 }
939
940 Geofence* geofences = new Geofence[geofenceRequestsCount];
destradaa1af4b022013-07-12 15:43:36 -0700941 if (geofences == NULL) {
942 ThrowOnError(env, FLP_RESULT_INSUFFICIENT_MEMORY, __FUNCTION__);
943 }
944
destradaa0682809a2013-08-12 18:50:30 -0700945 for (int i = 0; i < geofenceRequestsCount; ++i) {
946 geofences[i].data = new GeofenceData();
947 geofences[i].options = new GeofenceOptions();
948 jobject geofenceObject = env->GetObjectArrayElement(geofenceRequestsArray, i);
destradaa1af4b022013-07-12 15:43:36 -0700949
destradaa0682809a2013-08-12 18:50:30 -0700950 TranslateGeofenceFromGeofenceHardwareRequestParcelable(env, geofenceObject, geofences[i]);
destradaab75cb3a2013-08-23 17:26:16 -0700951 env->DeleteLocalRef(geofenceObject);
destradaa1af4b022013-07-12 15:43:36 -0700952 }
953
destradaa0682809a2013-08-12 18:50:30 -0700954 sFlpGeofencingInterface->add_geofences(geofenceRequestsCount, &geofences);
955 if (geofences != NULL) {
956 for(int i = 0; i < geofenceRequestsCount; ++i) {
957 delete geofences[i].data;
958 delete geofences[i].options;
959 }
960 delete[] geofences;
961 }
destradaa1af4b022013-07-12 15:43:36 -0700962}
963
Andreas Gampe184e3ed2014-09-29 15:04:06 -0700964static void PauseGeofence(JNIEnv* env, jobject /* object */, jint geofenceId) {
destradaa1af4b022013-07-12 15:43:36 -0700965 if(sFlpGeofencingInterface == NULL) {
966 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
967 }
968
969 sFlpGeofencingInterface->pause_geofence(geofenceId);
970}
971
972static void ResumeGeofence(
973 JNIEnv* env,
Andreas Gampe184e3ed2014-09-29 15:04:06 -0700974 jobject /* object */,
destradaa1af4b022013-07-12 15:43:36 -0700975 jint geofenceId,
976 jint monitorTransitions) {
977 if(sFlpGeofencingInterface == NULL) {
978 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
979 }
980
981 sFlpGeofencingInterface->resume_geofence(geofenceId, monitorTransitions);
982}
983
984static void ModifyGeofenceOption(
985 JNIEnv* env,
Andreas Gampe184e3ed2014-09-29 15:04:06 -0700986 jobject /* object */,
destradaa1af4b022013-07-12 15:43:36 -0700987 jint geofenceId,
988 jint lastTransition,
989 jint monitorTransitions,
990 jint notificationResponsiveness,
991 jint unknownTimer,
992 jint sourcesToUse) {
993 if(sFlpGeofencingInterface == NULL) {
994 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
995 }
996
997 GeofenceOptions options = {
998 lastTransition,
999 monitorTransitions,
1000 notificationResponsiveness,
1001 unknownTimer,
1002 (uint32_t)sourcesToUse
1003 };
1004
1005 sFlpGeofencingInterface->modify_geofence_option(geofenceId, &options);
1006}
1007
1008static void RemoveGeofences(
1009 JNIEnv* env,
Andreas Gampe184e3ed2014-09-29 15:04:06 -07001010 jobject /* object */,
destradaa1af4b022013-07-12 15:43:36 -07001011 jintArray geofenceIdsArray) {
1012 if(sFlpGeofencingInterface == NULL) {
1013 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
1014 }
1015
1016 jsize geofenceIdsCount = env->GetArrayLength(geofenceIdsArray);
1017 jint* geofenceIds = env->GetIntArrayElements(geofenceIdsArray, /* isCopy */ NULL);
1018 if(geofenceIds == NULL) {
1019 ThrowOnError(env, FLP_RESULT_ERROR, __FUNCTION__);
1020 }
1021
1022 sFlpGeofencingInterface->remove_geofences(geofenceIdsCount, geofenceIds);
destradaa7f02eb22013-09-20 13:08:41 -07001023 env->ReleaseIntArrayElements(geofenceIdsArray, geofenceIds, 0 /*mode*/);
destradaa1af4b022013-07-12 15:43:36 -07001024}
1025
Daniel Micay76f6a862015-09-19 17:31:01 -04001026static const JNINativeMethod sMethods[] = {
destradaa1af4b022013-07-12 15:43:36 -07001027 //{"name", "signature", functionPointer }
1028 {"nativeClassInit", "()V", reinterpret_cast<void*>(ClassInit)},
1029 {"nativeInit", "()V", reinterpret_cast<void*>(Init)},
1030 {"nativeCleanup", "()V", reinterpret_cast<void*>(Cleanup)},
1031 {"nativeIsSupported", "()Z", reinterpret_cast<void*>(IsSupported)},
1032 {"nativeGetBatchSize", "()I", reinterpret_cast<void*>(GetBatchSize)},
destradaa0682809a2013-08-12 18:50:30 -07001033 {"nativeStartBatching",
1034 "(ILandroid/location/FusedBatchOptions;)V",
destradaa1af4b022013-07-12 15:43:36 -07001035 reinterpret_cast<void*>(StartBatching)},
destradaa0682809a2013-08-12 18:50:30 -07001036 {"nativeUpdateBatchingOptions",
1037 "(ILandroid/location/FusedBatchOptions;)V",
destradaa1af4b022013-07-12 15:43:36 -07001038 reinterpret_cast<void*>(UpdateBatchingOptions)},
1039 {"nativeStopBatching", "(I)V", reinterpret_cast<void*>(StopBatching)},
destradaa0682809a2013-08-12 18:50:30 -07001040 {"nativeRequestBatchedLocation",
1041 "(I)V",
destradaa1af4b022013-07-12 15:43:36 -07001042 reinterpret_cast<void*>(GetBatchedLocation)},
David Christiefff30432015-04-12 21:26:02 -07001043 {"nativeFlushBatchedLocations",
1044 "()V",
1045 reinterpret_cast<void*>(FlushBatchedLocations)},
destradaa0682809a2013-08-12 18:50:30 -07001046 {"nativeInjectLocation",
1047 "(Landroid/location/Location;)V",
destradaa1af4b022013-07-12 15:43:36 -07001048 reinterpret_cast<void*>(InjectLocation)},
destradaa0682809a2013-08-12 18:50:30 -07001049 {"nativeIsDiagnosticSupported",
1050 "()Z",
destradaa1af4b022013-07-12 15:43:36 -07001051 reinterpret_cast<void*>(IsDiagnosticSupported)},
destradaa0682809a2013-08-12 18:50:30 -07001052 {"nativeInjectDiagnosticData",
1053 "(Ljava/lang/String;)V",
destradaa1af4b022013-07-12 15:43:36 -07001054 reinterpret_cast<void*>(InjectDiagnosticData)},
destradaa0682809a2013-08-12 18:50:30 -07001055 {"nativeIsDeviceContextSupported",
1056 "()Z",
destradaa1af4b022013-07-12 15:43:36 -07001057 reinterpret_cast<void*>(IsDeviceContextSupported)},
destradaa0682809a2013-08-12 18:50:30 -07001058 {"nativeInjectDeviceContext",
1059 "(I)V",
destradaa1af4b022013-07-12 15:43:36 -07001060 reinterpret_cast<void*>(InjectDeviceContext)},
destradaa0682809a2013-08-12 18:50:30 -07001061 {"nativeIsGeofencingSupported",
1062 "()Z",
destradaa1af4b022013-07-12 15:43:36 -07001063 reinterpret_cast<void*>(IsGeofencingSupported)},
destradaa0682809a2013-08-12 18:50:30 -07001064 {"nativeAddGeofences",
1065 "([Landroid/hardware/location/GeofenceHardwareRequestParcelable;)V",
destradaa1af4b022013-07-12 15:43:36 -07001066 reinterpret_cast<void*>(AddGeofences)},
1067 {"nativePauseGeofence", "(I)V", reinterpret_cast<void*>(PauseGeofence)},
1068 {"nativeResumeGeofence", "(II)V", reinterpret_cast<void*>(ResumeGeofence)},
destradaa0682809a2013-08-12 18:50:30 -07001069 {"nativeModifyGeofenceOption",
1070 "(IIIIII)V",
destradaa1af4b022013-07-12 15:43:36 -07001071 reinterpret_cast<void*>(ModifyGeofenceOption)},
1072 {"nativeRemoveGeofences", "([I)V", reinterpret_cast<void*>(RemoveGeofences)}
1073};
1074
1075/*
1076 * Registration method invoked on JNI Load.
1077 */
1078int register_android_server_location_FlpHardwareProvider(JNIEnv* env) {
1079 return jniRegisterNativeMethods(
1080 env,
1081 "com/android/server/location/FlpHardwareProvider",
1082 sMethods,
1083 NELEM(sMethods)
1084 );
1085}
1086
1087} /* name-space Android */