Home | History | Annotate | Download | only in jni
      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 //#define LOG_NDDEBUG 0
     20 
     21 #include "JNIHelp.h"
     22 #include "jni.h"
     23 #include "hardware_legacy/gps.h"
     24 #include "hardware_legacy/gps_ni.h"
     25 #include "utils/Log.h"
     26 #include "utils/misc.h"
     27 
     28 #include <string.h>
     29 #include <pthread.h>
     30 
     31 static pthread_mutex_t sEventMutex = PTHREAD_MUTEX_INITIALIZER;
     32 static pthread_cond_t sEventCond = PTHREAD_COND_INITIALIZER;
     33 static jmethodID method_reportLocation;
     34 static jmethodID method_reportStatus;
     35 static jmethodID method_reportSvStatus;
     36 static jmethodID method_reportAGpsStatus;
     37 static jmethodID method_reportNmea;
     38 static jmethodID method_xtraDownloadRequest;
     39 static jmethodID method_reportNiNotification;
     40 
     41 static const GpsInterface* sGpsInterface = NULL;
     42 static const GpsXtraInterface* sGpsXtraInterface = NULL;
     43 static const AGpsInterface* sAGpsInterface = NULL;
     44 static const GpsPrivacyInterface* sGpsPrivacyInterface = NULL;
     45 static const GpsNiInterface* sGpsNiInterface = NULL;
     46 static const GpsDebugInterface* sGpsDebugInterface = NULL;
     47 
     48 // data written to by GPS callbacks
     49 static GpsLocation  sGpsLocation;
     50 static GpsStatus    sGpsStatus;
     51 static GpsSvStatus  sGpsSvStatus;
     52 static AGpsStatus   sAGpsStatus;
     53 static GpsNiNotification  sGpsNiNotification;
     54 
     55 // buffer for NMEA data
     56 #define NMEA_SENTENCE_LENGTH    100
     57 #define NMEA_SENTENCE_COUNT     40
     58 struct NmeaSentence {
     59     GpsUtcTime  timestamp;
     60     char        nmea[NMEA_SENTENCE_LENGTH];
     61 };
     62 static NmeaSentence sNmeaBuffer[NMEA_SENTENCE_COUNT];
     63 static int mNmeaSentenceCount = 0;
     64 
     65 // a copy of the data shared by android_location_GpsLocationProvider_wait_for_event
     66 // and android_location_GpsLocationProvider_read_status
     67 static GpsLocation  sGpsLocationCopy;
     68 static GpsStatus    sGpsStatusCopy;
     69 static GpsSvStatus  sGpsSvStatusCopy;
     70 static AGpsStatus   sAGpsStatusCopy;
     71 static NmeaSentence sNmeaBufferCopy[NMEA_SENTENCE_COUNT];
     72 static GpsNiNotification  sGpsNiNotificationCopy;
     73 
     74 enum CallbackType {
     75     kLocation = 1,
     76     kStatus = 2,
     77     kSvStatus = 4,
     78     kAGpsStatus = 8,
     79     kXtraDownloadRequest = 16,
     80     kDisableRequest = 32,
     81     kNmeaAvailable = 64,
     82     kNiNotification = 128,
     83 };
     84 static int sPendingCallbacks;
     85 
     86 namespace android {
     87 
     88 static void location_callback(GpsLocation* location)
     89 {
     90     pthread_mutex_lock(&sEventMutex);
     91 
     92     sPendingCallbacks |= kLocation;
     93     memcpy(&sGpsLocation, location, sizeof(sGpsLocation));
     94 
     95     pthread_cond_signal(&sEventCond);
     96     pthread_mutex_unlock(&sEventMutex);
     97 }
     98 
     99 static void status_callback(GpsStatus* status)
    100 {
    101     pthread_mutex_lock(&sEventMutex);
    102 
    103     sPendingCallbacks |= kStatus;
    104     memcpy(&sGpsStatus, status, sizeof(sGpsStatus));
    105 
    106     pthread_cond_signal(&sEventCond);
    107     pthread_mutex_unlock(&sEventMutex);
    108 }
    109 
    110 static void sv_status_callback(GpsSvStatus* sv_status)
    111 {
    112     pthread_mutex_lock(&sEventMutex);
    113 
    114     sPendingCallbacks |= kSvStatus;
    115     memcpy(&sGpsSvStatus, sv_status, sizeof(GpsSvStatus));
    116 
    117     pthread_cond_signal(&sEventCond);
    118     pthread_mutex_unlock(&sEventMutex);
    119 }
    120 
    121 static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length)
    122 {
    123     pthread_mutex_lock(&sEventMutex);
    124 
    125     if (length >= NMEA_SENTENCE_LENGTH) {
    126         LOGE("NMEA data too long in nmea_callback (length = %d)\n", length);
    127         length = NMEA_SENTENCE_LENGTH - 1;
    128     }
    129     if (mNmeaSentenceCount >= NMEA_SENTENCE_COUNT) {
    130         LOGE("NMEA data overflowed buffer\n");
    131         pthread_mutex_unlock(&sEventMutex);
    132         return;
    133     }
    134 
    135     sPendingCallbacks |= kNmeaAvailable;
    136     sNmeaBuffer[mNmeaSentenceCount].timestamp = timestamp;
    137     memcpy(sNmeaBuffer[mNmeaSentenceCount].nmea, nmea, length);
    138     sNmeaBuffer[mNmeaSentenceCount].nmea[length] = 0;
    139     mNmeaSentenceCount++;
    140 
    141     pthread_cond_signal(&sEventCond);
    142     pthread_mutex_unlock(&sEventMutex);
    143 }
    144 
    145 static void agps_status_callback(AGpsStatus* agps_status)
    146 {
    147     pthread_mutex_lock(&sEventMutex);
    148 
    149     sPendingCallbacks |= kAGpsStatus;
    150     memcpy(&sAGpsStatus, agps_status, sizeof(AGpsStatus));
    151 
    152     pthread_cond_signal(&sEventCond);
    153     pthread_mutex_unlock(&sEventMutex);
    154 }
    155 
    156 GpsCallbacks sGpsCallbacks = {
    157     location_callback,
    158     status_callback,
    159     sv_status_callback,
    160     nmea_callback
    161 };
    162 
    163 static void
    164 download_request_callback()
    165 {
    166     pthread_mutex_lock(&sEventMutex);
    167     sPendingCallbacks |= kXtraDownloadRequest;
    168     pthread_cond_signal(&sEventCond);
    169     pthread_mutex_unlock(&sEventMutex);
    170 }
    171 
    172 static void
    173 gps_ni_notify_callback(GpsNiNotification *notification)
    174 {
    175    LOGD("gps_ni_notify_callback: notif=%d", notification->notification_id);
    176 
    177    pthread_mutex_lock(&sEventMutex);
    178 
    179    sPendingCallbacks |= kNiNotification;
    180    memcpy(&sGpsNiNotification, notification, sizeof(GpsNiNotification));
    181 
    182    pthread_cond_signal(&sEventCond);
    183    pthread_mutex_unlock(&sEventMutex);
    184 }
    185 
    186 GpsXtraCallbacks sGpsXtraCallbacks = {
    187     download_request_callback,
    188 };
    189 
    190 AGpsCallbacks sAGpsCallbacks = {
    191     agps_status_callback,
    192 };
    193 
    194 GpsNiCallbacks sGpsNiCallbacks = {
    195     gps_ni_notify_callback,
    196 };
    197 
    198 static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
    199     method_reportLocation = env->GetMethodID(clazz, "reportLocation", "(IDDDFFFJ)V");
    200     method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
    201     method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
    202     method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II)V");
    203     method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(IJ)V");
    204     method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
    205     method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification", "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
    206 }
    207 
    208 static jboolean android_location_GpsLocationProvider_is_supported(JNIEnv* env, jclass clazz) {
    209     if (!sGpsInterface)
    210         sGpsInterface = gps_get_interface();
    211     return (sGpsInterface != NULL);
    212 }
    213 
    214 static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)
    215 {
    216     if (!sGpsInterface)
    217         sGpsInterface = gps_get_interface();
    218     if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
    219         return false;
    220 
    221     if (!sAGpsInterface)
    222         sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
    223     if (sAGpsInterface)
    224         sAGpsInterface->init(&sAGpsCallbacks);
    225 
    226     if (!sGpsNiInterface)
    227         sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
    228     if (sGpsNiInterface)
    229         sGpsNiInterface->init(&sGpsNiCallbacks);
    230 
    231     // Clear privacy lock while enabled
    232     if (!sGpsPrivacyInterface)
    233         sGpsPrivacyInterface = (const GpsPrivacyInterface*)sGpsInterface->get_extension(GPS_PRIVACY_INTERFACE);
    234     if (sGpsPrivacyInterface)
    235         sGpsPrivacyInterface->set_privacy_lock(0);
    236 
    237     if (!sGpsDebugInterface)
    238        sGpsDebugInterface = (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE);
    239 
    240     return true;
    241 }
    242 
    243 static void android_location_GpsLocationProvider_disable(JNIEnv* env, jobject obj)
    244 {
    245     // Enable privacy lock while disabled
    246     if (!sGpsPrivacyInterface)
    247         sGpsPrivacyInterface = (const GpsPrivacyInterface*)sGpsInterface->get_extension(GPS_PRIVACY_INTERFACE);
    248     if (sGpsPrivacyInterface)
    249         sGpsPrivacyInterface->set_privacy_lock(1);
    250 
    251     pthread_mutex_lock(&sEventMutex);
    252     sPendingCallbacks |= kDisableRequest;
    253     pthread_cond_signal(&sEventCond);
    254     pthread_mutex_unlock(&sEventMutex);
    255 }
    256 
    257 static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject obj)
    258 {
    259     sGpsInterface->cleanup();
    260 }
    261 
    262 static jboolean android_location_GpsLocationProvider_start(JNIEnv* env, jobject obj, jint positionMode,
    263         jboolean singleFix, jint fixFrequency)
    264 {
    265     int result = sGpsInterface->set_position_mode(positionMode, (singleFix ? 0 : fixFrequency));
    266     if (result) {
    267         return false;
    268     }
    269 
    270     return (sGpsInterface->start() == 0);
    271 }
    272 
    273 static jboolean android_location_GpsLocationProvider_stop(JNIEnv* env, jobject obj)
    274 {
    275     return (sGpsInterface->stop() == 0);
    276 }
    277 
    278 static void android_location_GpsLocationProvider_delete_aiding_data(JNIEnv* env, jobject obj, jint flags)
    279 {
    280     sGpsInterface->delete_aiding_data(flags);
    281 }
    282 
    283 static void android_location_GpsLocationProvider_wait_for_event(JNIEnv* env, jobject obj)
    284 {
    285     pthread_mutex_lock(&sEventMutex);
    286     while (sPendingCallbacks == 0) {
    287         pthread_cond_wait(&sEventCond, &sEventMutex);
    288     }
    289 
    290     // copy and clear the callback flags
    291     int pendingCallbacks = sPendingCallbacks;
    292     sPendingCallbacks = 0;
    293     int nmeaSentenceCount = mNmeaSentenceCount;
    294     mNmeaSentenceCount = 0;
    295 
    296     // copy everything and unlock the mutex before calling into Java code to avoid the possibility
    297     // of timeouts in the GPS engine.
    298     if (pendingCallbacks & kLocation)
    299         memcpy(&sGpsLocationCopy, &sGpsLocation, sizeof(sGpsLocationCopy));
    300     if (pendingCallbacks & kStatus)
    301         memcpy(&sGpsStatusCopy, &sGpsStatus, sizeof(sGpsStatusCopy));
    302     if (pendingCallbacks & kSvStatus)
    303         memcpy(&sGpsSvStatusCopy, &sGpsSvStatus, sizeof(sGpsSvStatusCopy));
    304     if (pendingCallbacks & kAGpsStatus)
    305         memcpy(&sAGpsStatusCopy, &sAGpsStatus, sizeof(sAGpsStatusCopy));
    306     if (pendingCallbacks & kNmeaAvailable)
    307         memcpy(&sNmeaBufferCopy, &sNmeaBuffer, nmeaSentenceCount * sizeof(sNmeaBuffer[0]));
    308     if (pendingCallbacks & kNiNotification)
    309         memcpy(&sGpsNiNotificationCopy, &sGpsNiNotification, sizeof(sGpsNiNotificationCopy));
    310     pthread_mutex_unlock(&sEventMutex);
    311 
    312     if (pendingCallbacks & kLocation) {
    313         env->CallVoidMethod(obj, method_reportLocation, sGpsLocationCopy.flags,
    314                 (jdouble)sGpsLocationCopy.latitude, (jdouble)sGpsLocationCopy.longitude,
    315                 (jdouble)sGpsLocationCopy.altitude,
    316                 (jfloat)sGpsLocationCopy.speed, (jfloat)sGpsLocationCopy.bearing,
    317                 (jfloat)sGpsLocationCopy.accuracy, (jlong)sGpsLocationCopy.timestamp);
    318     }
    319     if (pendingCallbacks & kStatus) {
    320         env->CallVoidMethod(obj, method_reportStatus, sGpsStatusCopy.status);
    321     }
    322     if (pendingCallbacks & kSvStatus) {
    323         env->CallVoidMethod(obj, method_reportSvStatus);
    324     }
    325     if (pendingCallbacks & kAGpsStatus) {
    326         env->CallVoidMethod(obj, method_reportAGpsStatus, sAGpsStatusCopy.type, sAGpsStatusCopy.status);
    327     }
    328     if (pendingCallbacks & kNmeaAvailable) {
    329         for (int i = 0; i < nmeaSentenceCount; i++) {
    330             env->CallVoidMethod(obj, method_reportNmea, i, sNmeaBuffer[i].timestamp);
    331         }
    332     }
    333     if (pendingCallbacks & kXtraDownloadRequest) {
    334         env->CallVoidMethod(obj, method_xtraDownloadRequest);
    335     }
    336     if (pendingCallbacks & kDisableRequest) {
    337         // don't need to do anything - we are just poking so wait_for_event will return.
    338     }
    339     if (pendingCallbacks & kNiNotification) {
    340        LOGD("android_location_GpsLocationProvider_wait_for_event: sent notification callback.");
    341        jstring reqId = env->NewStringUTF(sGpsNiNotificationCopy.requestor_id);
    342        jstring text = env->NewStringUTF(sGpsNiNotificationCopy.text);
    343        jstring extras = env->NewStringUTF(sGpsNiNotificationCopy.extras);
    344        env->CallVoidMethod(obj, method_reportNiNotification,
    345              sGpsNiNotificationCopy.notification_id,
    346              sGpsNiNotificationCopy.ni_type,
    347              sGpsNiNotificationCopy.notify_flags,
    348              sGpsNiNotificationCopy.timeout,
    349              sGpsNiNotificationCopy.default_response,
    350              reqId,
    351              text,
    352              sGpsNiNotificationCopy.requestor_id_encoding,
    353              sGpsNiNotificationCopy.text_encoding,
    354              extras
    355        );
    356     }
    357 }
    358 
    359 static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject obj,
    360         jintArray prnArray, jfloatArray snrArray, jfloatArray elevArray, jfloatArray azumArray,
    361         jintArray maskArray)
    362 {
    363     // this should only be called from within a call to reportStatus, so we don't need to lock here
    364 
    365     jint* prns = env->GetIntArrayElements(prnArray, 0);
    366     jfloat* snrs = env->GetFloatArrayElements(snrArray, 0);
    367     jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
    368     jfloat* azim = env->GetFloatArrayElements(azumArray, 0);
    369     jint* mask = env->GetIntArrayElements(maskArray, 0);
    370 
    371     int num_svs = sGpsSvStatusCopy.num_svs;
    372     for (int i = 0; i < num_svs; i++) {
    373         prns[i] = sGpsSvStatusCopy.sv_list[i].prn;
    374         snrs[i] = sGpsSvStatusCopy.sv_list[i].snr;
    375         elev[i] = sGpsSvStatusCopy.sv_list[i].elevation;
    376         azim[i] = sGpsSvStatusCopy.sv_list[i].azimuth;
    377     }
    378     mask[0] = sGpsSvStatusCopy.ephemeris_mask;
    379     mask[1] = sGpsSvStatusCopy.almanac_mask;
    380     mask[2] = sGpsSvStatusCopy.used_in_fix_mask;
    381 
    382     env->ReleaseIntArrayElements(prnArray, prns, 0);
    383     env->ReleaseFloatArrayElements(snrArray, snrs, 0);
    384     env->ReleaseFloatArrayElements(elevArray, elev, 0);
    385     env->ReleaseFloatArrayElements(azumArray, azim, 0);
    386     env->ReleaseIntArrayElements(maskArray, mask, 0);
    387     return num_svs;
    388 }
    389 
    390 static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj, jint index, jbyteArray nmeaArray, jint buffer_size)
    391 {
    392     // this should only be called from within a call to reportNmea, so we don't need to lock here
    393 
    394     jbyte* nmea = env->GetByteArrayElements(nmeaArray, 0);
    395 
    396     int length = strlen(sNmeaBufferCopy[index].nmea);
    397     if (length > buffer_size)
    398         length = buffer_size;
    399     memcpy(nmea, sNmeaBufferCopy[index].nmea, length);
    400 
    401     env->ReleaseByteArrayElements(nmeaArray, nmea, 0);
    402     return length;
    403 }
    404 
    405 static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobject obj, jlong time,
    406         jlong timeReference, jint uncertainty)
    407 {
    408     sGpsInterface->inject_time(time, timeReference, uncertainty);
    409 }
    410 
    411 static void android_location_GpsLocationProvider_inject_location(JNIEnv* env, jobject obj,
    412         jdouble latitude, jdouble longitude, jfloat accuracy)
    413 {
    414     sGpsInterface->inject_location(latitude, longitude, accuracy);
    415 }
    416 
    417 static jboolean android_location_GpsLocationProvider_supports_xtra(JNIEnv* env, jobject obj)
    418 {
    419     if (!sGpsXtraInterface) {
    420         sGpsXtraInterface = (const GpsXtraInterface*)sGpsInterface->get_extension(GPS_XTRA_INTERFACE);
    421         if (sGpsXtraInterface) {
    422             int result = sGpsXtraInterface->init(&sGpsXtraCallbacks);
    423             if (result) {
    424                 sGpsXtraInterface = NULL;
    425             }
    426         }
    427     }
    428 
    429     return (sGpsXtraInterface != NULL);
    430 }
    431 
    432 static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject obj,
    433         jbyteArray data, jint length)
    434 {
    435     jbyte* bytes = env->GetByteArrayElements(data, 0);
    436     sGpsXtraInterface->inject_xtra_data((char *)bytes, length);
    437     env->ReleaseByteArrayElements(data, bytes, 0);
    438 }
    439 
    440 static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env, jobject obj, jstring apn)
    441 {
    442     if (!sAGpsInterface) {
    443         sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
    444     }
    445     if (sAGpsInterface) {
    446         if (apn == NULL) {
    447             jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
    448             return;
    449         }
    450         const char *apnStr = env->GetStringUTFChars(apn, NULL);
    451         sAGpsInterface->data_conn_open(apnStr);
    452         env->ReleaseStringUTFChars(apn, apnStr);
    453     }
    454 }
    455 
    456 static void android_location_GpsLocationProvider_agps_data_conn_closed(JNIEnv* env, jobject obj)
    457 {
    458     if (!sAGpsInterface) {
    459         sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
    460     }
    461     if (sAGpsInterface) {
    462         sAGpsInterface->data_conn_closed();
    463     }
    464 }
    465 
    466 static void android_location_GpsLocationProvider_agps_data_conn_failed(JNIEnv* env, jobject obj)
    467 {
    468     if (!sAGpsInterface) {
    469         sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
    470     }
    471     if (sAGpsInterface) {
    472         sAGpsInterface->data_conn_failed();
    473     }
    474 }
    475 
    476 static void android_location_GpsLocationProvider_set_agps_server(JNIEnv* env, jobject obj,
    477         jint type, jstring hostname, jint port)
    478 {
    479     if (!sAGpsInterface) {
    480         sAGpsInterface = (const AGpsInterface*)sGpsInterface->get_extension(AGPS_INTERFACE);
    481     }
    482     if (sAGpsInterface) {
    483         const char *c_hostname = env->GetStringUTFChars(hostname, NULL);
    484         sAGpsInterface->set_server(type, c_hostname, port);
    485         env->ReleaseStringUTFChars(hostname, c_hostname);
    486     }
    487 }
    488 
    489 static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* env, jobject obj,
    490       jint notifId, jint response)
    491 {
    492     if (!sGpsNiInterface)
    493         sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
    494     if (sGpsNiInterface)
    495         sGpsNiInterface->respond(notifId, response);
    496 }
    497 
    498 static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* env, jobject obj)
    499 {
    500     jstring result = NULL;
    501     if (sGpsDebugInterface) {
    502         const size_t maxLength = 2047;
    503         char buffer[maxLength+1];
    504         size_t length = sGpsDebugInterface->get_internal_state(buffer, maxLength);
    505         if (length > maxLength) length = maxLength;
    506         buffer[length] = 0;
    507         result = env->NewStringUTF(buffer);
    508     }
    509     return result;
    510 }
    511 
    512 static JNINativeMethod sMethods[] = {
    513      /* name, signature, funcPtr */
    514     {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
    515     {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported},
    516     {"native_init", "()Z", (void*)android_location_GpsLocationProvider_init},
    517     {"native_disable", "()V", (void*)android_location_GpsLocationProvider_disable},
    518     {"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup},
    519     {"native_start", "(IZI)Z", (void*)android_location_GpsLocationProvider_start},
    520     {"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop},
    521     {"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data},
    522     {"native_wait_for_event", "()V", (void*)android_location_GpsLocationProvider_wait_for_event},
    523     {"native_read_sv_status", "([I[F[F[F[I)I", (void*)android_location_GpsLocationProvider_read_sv_status},
    524     {"native_read_nmea", "(I[BI)I", (void*)android_location_GpsLocationProvider_read_nmea},
    525     {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
    526     {"native_inject_location", "(DDF)V", (void*)android_location_GpsLocationProvider_inject_location},
    527     {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},
    528     {"native_inject_xtra_data", "([BI)V", (void*)android_location_GpsLocationProvider_inject_xtra_data},
    529     {"native_agps_data_conn_open", "(Ljava/lang/String;)V", (void*)android_location_GpsLocationProvider_agps_data_conn_open},
    530     {"native_agps_data_conn_closed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_closed},
    531     {"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
    532     {"native_set_agps_server", "(ILjava/lang/String;I)V", (void*)android_location_GpsLocationProvider_set_agps_server},
    533     {"native_send_ni_response", "(II)V", (void*)android_location_GpsLocationProvider_send_ni_response},
    534     {"native_get_internal_state", "()Ljava/lang/String;", (void*)android_location_GpsLocationProvider_get_internal_state},
    535 };
    536 
    537 int register_android_location_GpsLocationProvider(JNIEnv* env)
    538 {
    539     return jniRegisterNativeMethods(env, "com/android/internal/location/GpsLocationProvider", sMethods, NELEM(sMethods));
    540 }
    541 
    542 } /* namespace android */
    543