1/* 2 * Copyright (C) 2008 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/licenses/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 "GpsLocationProvider" 18 19#include "JNIHelp.h" 20#include "jni.h" 21#include "hardware_legacy/gps.h" 22#include "utils/Log.h" 23#include "utils/misc.h" 24 25#include <string.h> 26#include <pthread.h> 27 28 29static pthread_mutex_t sEventMutex = PTHREAD_MUTEX_INITIALIZER; 30static pthread_cond_t sEventCond = PTHREAD_COND_INITIALIZER; 31static jmethodID method_reportLocation; 32static jmethodID method_reportStatus; 33static jmethodID method_reportSvStatus; 34static jmethodID method_reportAGpsStatus; 35static jmethodID method_xtraDownloadRequest; 36 37static const GpsInterface* sGpsInterface = NULL; 38static const GpsXtraInterface* sGpsXtraInterface = NULL; 39static const AGpsInterface* sAGpsInterface = NULL; 40 41// data written to by GPS callbacks 42static GpsLocation sGpsLocation; 43static GpsStatus sGpsStatus; 44static GpsSvStatus sGpsSvStatus; 45static AGpsStatus sAGpsStatus; 46 47// a copy of the data shared by android_location_GpsLocationProvider_wait_for_event 48// and android_location_GpsLocationProvider_read_status 49static GpsLocation sGpsLocationCopy; 50static GpsStatus sGpsStatusCopy; 51static GpsSvStatus sGpsSvStatusCopy; 52static AGpsStatus sAGpsStatusCopy; 53 54enum CallbackType { 55 kLocation = 1, 56 kStatus = 2, 57 kSvStatus = 4, 58 kAGpsStatus = 8, 59 kXtraDownloadRequest = 16, 60 kDisableRequest = 32, 61}; 62static int sPendingCallbacks; 63 64namespace android { 65 66static void location_callback(GpsLocation* location) 67{ 68 pthread_mutex_lock(&sEventMutex); 69 70 sPendingCallbacks |= kLocation; 71 memcpy(&sGpsLocation, location, sizeof(sGpsLocation)); 72 73 pthread_cond_signal(&sEventCond); 74 pthread_mutex_unlock(&sEventMutex); 75} 76 77static void status_callback(GpsStatus* status) 78{ 79 pthread_mutex_lock(&sEventMutex); 80 81 sPendingCallbacks |= kStatus; 82 memcpy(&sGpsStatus, status, sizeof(sGpsStatus)); 83 84 pthread_cond_signal(&sEventCond); 85 pthread_mutex_unlock(&sEventMutex); 86} 87 88static void sv_status_callback(GpsSvStatus* sv_status) 89{ 90 pthread_mutex_lock(&sEventMutex); 91 92 sPendingCallbacks |= kSvStatus; 93 memcpy(&sGpsSvStatus, sv_status, sizeof(GpsSvStatus)); 94 95 pthread_cond_signal(&sEventCond); 96 pthread_mutex_unlock(&sEventMutex); 97} 98 99static void agps_status_callback(AGpsStatus* agps_status) 100{ 101 pthread_mutex_lock(&sEventMutex); 102 103 sPendingCallbacks |= kAGpsStatus; 104 memcpy(&sAGpsStatus, agps_status, sizeof(AGpsStatus)); 105 106 pthread_cond_signal(&sEventCond); 107 pthread_mutex_unlock(&sEventMutex); 108} 109 110GpsCallbacks sGpsCallbacks = { 111 location_callback, 112 status_callback, 113 sv_status_callback, 114}; 115 116static void 117download_request_callback() 118{ 119 pthread_mutex_lock(&sEventMutex); 120 sPendingCallbacks |= kXtraDownloadRequest; 121 pthread_cond_signal(&sEventCond); 122 pthread_mutex_unlock(&sEventMutex); 123} 124 125GpsXtraCallbacks sGpsXtraCallbacks = { 126 download_request_callback, 127}; 128 129AGpsCallbacks sAGpsCallbacks = { 130 agps_status_callback, 131}; 132 133static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) { 134 method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V"); 135 method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V"); 136 method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V"); 137 method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II)V"); 138 method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V"); 139} 140 141static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) { 142 if (!sGpsInterface) 143 sGpsInterface = gps_get_interface(); 144 return (sGpsInterface != NULL); 145} 146 147static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj) 148{ 149 if (!sGpsInterface) 150 sGpsInterface = gps_get_interface(); 151 if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0) 152 return false; 153 154 if (!sAGpsInterface) 155 sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); 156 if (sAGpsInterface) 157 sAGpsInterface->init(&sAGpsCallbacks); 158 return true; 159} 160 161static void android_location_GpsLocationProvider_disable(JNIEnv* env, jobject obj) 162{ 163 pthread_mutex_lock(&sEventMutex); 164 sPendingCallbacks |= kDisableRequest; 165 pthread_cond_signal(&sEventCond); 166 pthread_mutex_unlock(&sEventMutex); 167} 168 169static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject obj) 170{ 171 sGpsInterface->cleanup(); 172} 173 174static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj, jint positionMode, 175 jboolean singleFix, jint fixFrequency) 176{ 177 int result = sGpsInterface->set_position_mode(positionMode, (singleFix ? 0 : fixFrequency)); 178 if (result) { 179 return false; 180 } 181 182 return (sGpsInterface->start() == 0); 183} 184 185static jboolean android_location_GpsLocationProvider_stop(JNIEnv* env, jobject obj) 186{ 187 return (sGpsInterface->stop() == 0); 188} 189 190static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* env, jobject obj, jint flags) 191{ 192 sGpsInterface->delete_aiding_data(flags); 193} 194 195static void android_location_GpsLocationProvider_wait_for_event(JNIEnv* env, jobject obj) 196{ 197 pthread_mutex_lock(&sEventMutex); 198 pthread_cond_wait(&sEventCond, &sEventMutex); 199 200 // copy and clear the callback flags 201 int pendingCallbacks = sPendingCallbacks; 202 sPendingCallbacks = 0; 203 204 // copy everything and unlock the mutex before calling into Java code to avoid the possibility 205 // of timeouts in the GPS engine. 206 memcpy(&sGpsLocationCopy, &sGpsLocation, sizeof(sGpsLocationCopy)); 207 memcpy(&sGpsStatusCopy, &sGpsStatus, sizeof(sGpsStatusCopy)); 208 memcpy(&sGpsSvStatusCopy, &sGpsSvStatus, sizeof(sGpsSvStatusCopy)); 209 memcpy(&sAGpsStatusCopy, &sAGpsStatus, sizeof(sAGpsStatusCopy)); 210 pthread_mutex_unlock(&sEventMutex); 211 212 if (pendingCallbacks & kLocation) { 213 env->CallVoidMethod(obj, method_reportLocation, sGpsLocationCopy.flags, 214 (jdouble)sGpsLocationCopy.latitude, (jdouble)sGpsLocationCopy.longitude, 215 (jdouble)sGpsLocationCopy.altitude, 216 (jfloat)sGpsLocationCopy.speed, (jfloat)sGpsLocationCopy.bearing, 217 (jfloat)sGpsLocationCopy.accuracy, (jlong)sGpsLocationCopy.timestamp); 218 } 219 if (pendingCallbacks & kStatus) { 220 env->CallVoidMethod(obj, method_reportStatus, sGpsStatusCopy.status); 221 } 222 if (pendingCallbacks & kSvStatus) { 223 env->CallVoidMethod(obj, method_reportSvStatus); 224 } 225 if (pendingCallbacks & kAGpsStatus) { 226 env->CallVoidMethod(obj, method_reportAGpsStatus, sAGpsStatusCopy.type, sAGpsStatusCopy.status); 227 } 228 if (pendingCallbacks & kXtraDownloadRequest) { 229 env->CallVoidMethod(obj, method_xtraDownloadRequest); 230 } 231 if (pendingCallbacks & kDisableRequest) { 232 // don't need to do anything - we are just poking so wait_for_event will return. 233 } 234} 235 236static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject obj, 237 jintArray prnArray, jfloatArray snrArray, jfloatArray elevArray, jfloatArray azumArray, 238 jintArray maskArray) 239{ 240 // this should only be called from within a call to reportStatus, so we don't need to lock here 241 242 jint* prns = env->GetIntArrayElements(prnArray, 0); 243 jfloat* snrs = env->GetFloatArrayElements(snrArray, 0); 244 jfloat* elev = env->GetFloatArrayElements(elevArray, 0); 245 jfloat* azim = env->GetFloatArrayElements(azumArray, 0); 246 jint* mask = env->GetIntArrayElements(maskArray, 0); 247 248 int num_svs = sGpsSvStatusCopy.num_svs; 249 for (int i = 0; i < num_svs; i++) { 250 prns[i] = sGpsSvStatusCopy.sv_list[i].prn; 251 snrs[i] = sGpsSvStatusCopy.sv_list[i].snr; 252 elev[i] = sGpsSvStatusCopy.sv_list[i].elevation; 253 azim[i] = sGpsSvStatusCopy.sv_list[i].azimuth; 254 } 255 mask[0] = sGpsSvStatusCopy.ephemeris_mask; 256 mask[1] = sGpsSvStatusCopy.almanac_mask; 257 mask[2] = sGpsSvStatusCopy.used_in_fix_mask; 258 259 env->ReleaseIntArrayElements(prnArray, prns, 0); 260 env->ReleaseFloatArrayElements(snrArray, snrs, 0); 261 env->ReleaseFloatArrayElements(elevArray, elev, 0); 262 env->ReleaseFloatArrayElements(azumArray, azim, 0); 263 env->ReleaseIntArrayElements(maskArray, mask, 0); 264 return num_svs; 265} 266 267static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobject obj, jlong time, 268 jlong timeReference, jint uncertainty) 269{ 270 sGpsInterface->inject_time(time, timeReference, uncertainty); 271} 272 273static void android_location_GpsLocationProvider_inject_location(JNIEnv* env, jobject obj, 274 jdouble latitude, jdouble longitude, jfloat accuracy) 275{ 276 sGpsInterface->inject_location(latitude, longitude, accuracy); 277} 278 279static jboolean android_location_GpsLocationProvider_supports_xtra(JNIEnv* env, jobject obj) 280{ 281 if (!sGpsXtraInterface) { 282 sGpsXtraInterface = (const GpsXtraInterface*)sGpsInterface->get_extension(GPS_XTRA_INTERFACE); 283 if (sGpsXtraInterface) { 284 int result = sGpsXtraInterface->init(&sGpsXtraCallbacks); 285 if (result) { 286 sGpsXtraInterface = NULL; 287 } 288 } 289 } 290 291 return (sGpsXtraInterface != NULL); 292} 293 294static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject obj, 295 jbyteArray data, jint length) 296{ 297 jbyte* bytes = env->GetByteArrayElements(data, 0); 298 sGpsXtraInterface->inject_xtra_data((char *)bytes, length); 299 env->ReleaseByteArrayElements(data, bytes, 0); 300} 301 302static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env, jobject obj, jstring apn) 303{ 304 if (!sAGpsInterface) { 305 sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); 306 } 307 if (sAGpsInterface) { 308 if (apn == NULL) { 309 jniThrowException(env, "java/lang/IllegalArgumentException", NULL); 310 return; 311 } 312 const char *apnStr = env->GetStringUTFChars(apn, NULL); 313 sAGpsInterface->data_conn_open(apnStr); 314 env->ReleaseStringUTFChars(apn, apnStr); 315 } 316} 317 318static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* env, jobject obj) 319{ 320 if (!sAGpsInterface) { 321 sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); 322 } 323 if (sAGpsInterface) { 324 sAGpsInterface->data_conn_closed(); 325 } 326} 327 328static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* env, jobject obj) 329{ 330 if (!sAGpsInterface) { 331 sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); 332 } 333 if (sAGpsInterface) { 334 sAGpsInterface->data_conn_failed(); 335 } 336} 337 338static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject obj, 339 jint type, jstring hostname, jint port) 340{ 341 if (!sAGpsInterface) { 342 sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE); 343 } 344 if (sAGpsInterface) { 345 const char *c_hostname = env->GetStringUTFChars(hostname, NULL); 346 sAGpsInterface->set_server(type, c_hostname, port); 347 env->ReleaseStringUTFChars(hostname, c_hostname); 348 } 349} 350 351static JNINativeMethod sMethods[] = { 352 /* name, signature, funcPtr */ 353 {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native}, 354 {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported}, 355 {"native_init", "()Z", (void*)android_location_GpsLocationProvider_init}, 356 {"native_disable", "()V", (void*)android_location_GpsLocationProvider_disable}, 357 {"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup}, 358 {"native_start", "(IZI)Z", (void*)android_location_GpsLocationProvider_start}, 359 {"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop}, 360 {"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data}, 361 {"native_wait_for_event", "()V", (void*)android_location_GpsLocationProvider_wait_for_event}, 362 {"native_read_sv_status", "([I[F[F[F[I)I", (void*)android_location_GpsLocationProvider_read_sv_status}, 363 {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time}, 364 {"native_inject_location", "(DDF)V", (void*)android_location_GpsLocationProvider_inject_location}, 365 {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra}, 366 {"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data}, 367 {"native_agps_data_conn_open", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open}, 368 {"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed}, 369 {"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed}, 370 {"native_set_agps_server", "(ILjava/lang/String;I)V", (void*)android_location_GpsLocationProvider_set_agps_server}, 371}; 372 373int register_android_location_GpsLocationProvider(JNIEnv* env) 374{ 375 return jniRegisterNativeMethods(env, "com/android/internal/location/GpsLocationProvider", sMethods, NELEM(sMethods)); 376} 377 378} /* namespace android */ 379