GPS: remove GpsEventThread from GpsLocationProvider

Rather than polling for events from the native code in an event thread,
we now require the GPS HAL libraries to call our callbacks from a thread
that is registered with the JVM to call directly into Java.
This eliminates a thread from our code and removes one step in the chain
of message passing from the GPS to the Location Manager client.

Change-Id: I2745a157690310ba9a699a8369f54a7366c6b1ba
Signed-off-by: Mike Lockwood <lockwood@android.com>
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 466642a..3e69c78 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -1136,11 +1136,13 @@
  *
  * This is called from elsewhere in the library.
  */
-/*static*/ void AndroidRuntime::createJavaThread(const char* name,
+/*static*/ android_thread_id_t AndroidRuntime::createJavaThread(const char* name,
     void (*start)(void *), void* arg)
 {
+    android_thread_id_t threadId = 0;
     javaCreateThreadEtc((android_thread_func_t) start, arg, name,
-        ANDROID_PRIORITY_DEFAULT, 0, NULL);
+        ANDROID_PRIORITY_DEFAULT, 0, &threadId);
+    return threadId;
 }
 
 #if 0
diff --git a/include/android_runtime/AndroidRuntime.h b/include/android_runtime/AndroidRuntime.h
index 99ab2f0..97a96b2 100644
--- a/include/android_runtime/AndroidRuntime.h
+++ b/include/android_runtime/AndroidRuntime.h
@@ -87,7 +87,7 @@
     virtual void onExit(int code);
 
     /** create a new thread that is visible from Java */
-    static void createJavaThread(const char* name, void (*start)(void *),
+    static android_thread_id_t createJavaThread(const char* name, void (*start)(void *),
         void* arg);
 
     /** return a pointer to the VM running in this process */
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 0cf67a3..4b4c784 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -226,8 +226,6 @@
     private Handler mHandler;
     // Used to signal when our main thread has initialized everything
     private final CountDownLatch mInitializedLatch = new CountDownLatch(1);
-    // Thread for receiving events from the native code
-    private Thread mEventThread;
 
     private String mAGpsApn;
     private int mAGpsDataConnectionState;
@@ -643,10 +641,6 @@
             if (mC2KServerHost != null) {
                 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
             }
-
-            // run event listener thread while we are enabled
-            mEventThread = new GpsEventThread();
-            mEventThread.start();
         } else {
             Log.w(TAG, "Failed to enable location provider");
         }
@@ -669,29 +663,9 @@
 
         mEnabled = false;
         stopNavigating();
-        native_disable();
-
-        // make sure our event thread exits
-        if (mEventThread != null) {
-            try {
-                mEventThread.join();
-            } catch (InterruptedException e) {
-                Log.w(TAG, "InterruptedException when joining mEventThread");
-            }
-            mEventThread = null;
-        }
 
         // do this before releasing wakelock
         native_cleanup();
-
-        // The GpsEventThread does not wait for the GPS to shutdown
-        // so we need to report the GPS_STATUS_ENGINE_OFF event here
-        if (mNavigating) {
-            reportStatus(GPS_STATUS_SESSION_END);
-        }
-        if (mEngineOn) {
-            reportStatus(GPS_STATUS_ENGINE_OFF);
-        }
     }
 
     public boolean isEnabled() {
@@ -1231,12 +1205,12 @@
     /**
      * called from native code to report NMEA data received
      */
-    private void reportNmea(int index, long timestamp) {
+    private void reportNmea(long timestamp) {
         synchronized(mListeners) {
             int size = mListeners.size();
             if (size > 0) {
                 // don't bother creating the String if we have no listeners
-                int length = native_read_nmea(index, mNmeaBuffer, mNmeaBuffer.length);
+                int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
                 String nmea = new String(mNmeaBuffer, 0, length);
 
                 for (int i = 0; i < size; i++) {
@@ -1359,28 +1333,6 @@
 		mNIHandler.handleNiNotification(notification);		
 	}
 
-    // this thread is used to receive events from the native code.
-    // native_wait_for_event() will callback to us via reportLocation(), reportStatus(), etc.
-    // this is necessary because native code cannot call Java on a thread that the JVM does
-    // not know about.
-    private final class GpsEventThread extends Thread {
-
-        public GpsEventThread() {
-            super("GpsEventThread");
-        }
-
-        public void run() {
-            if (DEBUG) Log.d(TAG, "GpsEventThread starting");
-            // Exit as soon as disable() is called instead of waiting for the GPS to stop.
-            while (mEnabled) {
-                // this will wait for an event from the GPS,
-                // which will be reported via reportLocation or reportStatus
-                native_wait_for_event();
-            }
-            if (DEBUG) Log.d(TAG, "GpsEventThread exiting");
-        }
-    }
-
     private void sendMessage(int message, int arg, Object obj) {
         // hold a wake lock while messages are pending
         synchronized (mWakeLock) {
@@ -1485,19 +1437,17 @@
     private static native boolean native_is_supported();
 
     private native boolean native_init();
-    private native void native_disable();
     private native void native_cleanup();
     private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
             int preferred_accuracy, int preferred_time);
     private native boolean native_start();
     private native boolean native_stop();
     private native void native_delete_aiding_data(int flags);
-    private native void native_wait_for_event();
     // returns number of SVs
     // mask[0] is ephemeris mask and mask[1] is almanac mask
     private native int native_read_sv_status(int[] svs, float[] snrs,
             float[] elevations, float[] azimuths, int[] masks);
-    private native int native_read_nmea(int index, byte[] buffer, int bufferSize);
+    private native int native_read_nmea(byte[] buffer, int bufferSize);
     private native void native_inject_location(double latitude, double longitude, float accuracy);
 
     // XTRA Support
diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp
index afd6ca8..0b41dd8 100755
--- a/services/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -25,12 +25,13 @@
 #include "hardware_legacy/power.h"
 #include "utils/Log.h"
 #include "utils/misc.h"
+#include "android_runtime/AndroidRuntime.h"
 
 #include <string.h>
 #include <pthread.h>
 
-static pthread_mutex_t sEventMutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t sEventCond = PTHREAD_COND_INITIALIZER;
+static jobject mCallbacksObj = NULL;
+
 static jmethodID method_reportLocation;
 static jmethodID method_reportStatus;
 static jmethodID method_reportSvStatus;
@@ -46,140 +47,89 @@
 static const GpsNiInterface* sGpsNiInterface = NULL;
 static const GpsDebugInterface* sGpsDebugInterface = NULL;
 
-// data written to by GPS callbacks
-static GpsLocation  sGpsLocation;
-static GpsStatus    sGpsStatus;
+// temporary storage for GPS callbacks
 static GpsSvStatus  sGpsSvStatus;
-static AGpsStatus   sAGpsStatus;
-static GpsNiNotification  sGpsNiNotification;
+static const char* sNmeaString;
+static int sNmeaStringLength;
 
 #define WAKE_LOCK_NAME  "GPS"
 
-// buffer for NMEA data
-#define NMEA_SENTENCE_LENGTH    100
-#define NMEA_SENTENCE_COUNT     40
-struct NmeaSentence {
-    GpsUtcTime  timestamp;
-    char        nmea[NMEA_SENTENCE_LENGTH];
-};
-static NmeaSentence sNmeaBuffer[NMEA_SENTENCE_COUNT];
-static int mNmeaSentenceCount = 0;
-
-// a copy of the data shared by android_location_GpsLocationProvider_wait_for_event
-// and android_location_GpsLocationProvider_read_status
-static GpsLocation  sGpsLocationCopy;
-static GpsStatus    sGpsStatusCopy;
-static GpsSvStatus  sGpsSvStatusCopy;
-static AGpsStatus   sAGpsStatusCopy;
-static NmeaSentence sNmeaBufferCopy[NMEA_SENTENCE_COUNT];
-static GpsNiNotification  sGpsNiNotificationCopy;
-static uint32_t     sEngineCapabilities;
-
-
-enum CallbackType {
-    kLocation = 1,
-    kStatus = 2,
-    kSvStatus = 4,
-    kAGpsStatus = 8,
-    kXtraDownloadRequest = 16,
-    kDisableRequest = 32,
-    kNmeaAvailable = 64,
-    kNiNotification = 128,
-    kSetCapabilities = 256,
-}; 
-static int sPendingCallbacks;
-
 namespace android {
 
+static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+    if (env->ExceptionCheck()) {
+        LOGE("An exception was thrown by callback '%s'.", methodName);
+        LOGE_EX(env);
+        env->ExceptionClear();
+    }
+}
+
 static void location_callback(GpsLocation* location)
 {
-    pthread_mutex_lock(&sEventMutex);
-
-    sPendingCallbacks |= kLocation;
-    memcpy(&sGpsLocation, location, sizeof(sGpsLocation));
-
-    pthread_cond_signal(&sEventCond);
-    pthread_mutex_unlock(&sEventMutex);
+    LOGD("location_callback\n");
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj, method_reportLocation, location->flags,
+            (jdouble)location->latitude, (jdouble)location->longitude,
+            (jdouble)location->altitude,
+            (jfloat)location->speed, (jfloat)location->bearing,
+            (jfloat)location->accuracy, (jlong)location->timestamp);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
 }
 
 static void status_callback(GpsStatus* status)
 {
-    pthread_mutex_lock(&sEventMutex);
-
-    sPendingCallbacks |= kStatus;
-    memcpy(&sGpsStatus, status, sizeof(sGpsStatus));
-
-    pthread_cond_signal(&sEventCond);
-    pthread_mutex_unlock(&sEventMutex);
+    LOGD("status_callback\n");
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    LOGD("env: %p obj: %p\n", env, mCallbacksObj);
+    env->CallVoidMethod(mCallbacksObj, method_reportStatus, status->status);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
 }
 
 static void sv_status_callback(GpsSvStatus* sv_status)
 {
-    pthread_mutex_lock(&sEventMutex);
-
-    sPendingCallbacks |= kSvStatus;
-    memcpy(&sGpsSvStatus, sv_status, sizeof(GpsSvStatus));
-
-    pthread_cond_signal(&sEventCond);
-    pthread_mutex_unlock(&sEventMutex);
+    LOGD("sv_status_callback\n");
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    memcpy(&sGpsSvStatus, sv_status, sizeof(sGpsSvStatus));
+    env->CallVoidMethod(mCallbacksObj, method_reportSvStatus);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
 }
 
 static void nmea_callback(GpsUtcTime timestamp, const char* nmea, int length)
 {
-    pthread_mutex_lock(&sEventMutex);
-
-    if (length >= NMEA_SENTENCE_LENGTH) {
-        LOGE("NMEA data too long in nmea_callback (length = %d)\n", length);
-        length = NMEA_SENTENCE_LENGTH - 1;
-    }
-    if (mNmeaSentenceCount >= NMEA_SENTENCE_COUNT) {
-        LOGE("NMEA data overflowed buffer\n");
-        pthread_mutex_unlock(&sEventMutex);
-        return;
-    }
-
-    sPendingCallbacks |= kNmeaAvailable;
-    sNmeaBuffer[mNmeaSentenceCount].timestamp = timestamp;
-    memcpy(sNmeaBuffer[mNmeaSentenceCount].nmea, nmea, length);
-    sNmeaBuffer[mNmeaSentenceCount].nmea[length] = 0;
-    mNmeaSentenceCount++;
-
-    pthread_cond_signal(&sEventCond);
-    pthread_mutex_unlock(&sEventMutex);
+    LOGD("nmea_callback\n");
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    // The Java code will call back to read these values
+    // We do this to avoid creating unnecessary String objects
+    sNmeaString = nmea;
+    sNmeaStringLength = length;
+    env->CallVoidMethod(mCallbacksObj, method_reportNmea, timestamp);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
 }
 
 static void set_capabilities_callback(uint32_t capabilities)
 {
-   LOGD("set_capabilities_callback: %08X", capabilities);
-
-   pthread_mutex_lock(&sEventMutex);
-
-   sPendingCallbacks |= kSetCapabilities;
-   sEngineCapabilities = capabilities;
-
-   pthread_cond_signal(&sEventCond);
-   pthread_mutex_unlock(&sEventMutex);
+    LOGD("set_capabilities_callback\n");
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj, method_setEngineCapabilities, capabilities);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
 }
 
 static void acquire_wakelock_callback()
 {
+    LOGD("acquire_wakelock_callback\n");
     acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_NAME);
 }
 
 static void release_wakelock_callback()
 {
+    LOGD("release_wakelock_callback\n");
     release_wake_lock(WAKE_LOCK_NAME);
 }
 
-static void agps_status_callback(AGpsStatus* agps_status)
+static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)
 {
-    pthread_mutex_lock(&sEventMutex);
-
-    sPendingCallbacks |= kAGpsStatus;
-    memcpy(&sAGpsStatus, agps_status, sizeof(AGpsStatus));
-
-    pthread_cond_signal(&sEventCond);
-    pthread_mutex_unlock(&sEventMutex);
+    LOGD("create_thread_callback\n");
+    return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);
 }
 
 GpsCallbacks sGpsCallbacks = {
@@ -191,41 +141,67 @@
     set_capabilities_callback,
     acquire_wakelock_callback,
     release_wakelock_callback,
+    create_thread_callback,
 };
 
-static void
-download_request_callback()
+static void xtra_download_request_callback()
 {
-    pthread_mutex_lock(&sEventMutex);
-    sPendingCallbacks |= kXtraDownloadRequest;
-    pthread_cond_signal(&sEventCond);
-    pthread_mutex_unlock(&sEventMutex);
-}
-
-static void
-gps_ni_notify_callback(GpsNiNotification *notification)
-{
-   LOGD("gps_ni_notify_callback: notif=%d", notification->notification_id);
-
-   pthread_mutex_lock(&sEventMutex);
-
-   sPendingCallbacks |= kNiNotification;
-   memcpy(&sGpsNiNotification, notification, sizeof(GpsNiNotification));
-
-   pthread_cond_signal(&sEventCond);
-   pthread_mutex_unlock(&sEventMutex);
+    LOGD("xtra_download_request_callback\n");
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj, method_xtraDownloadRequest);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
 }
 
 GpsXtraCallbacks sGpsXtraCallbacks = {
-    download_request_callback,
+    xtra_download_request_callback,
+    create_thread_callback,
 };
 
+static void agps_status_callback(AGpsStatus* agps_status)
+{
+    LOGD("agps_status_callback\n");
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mCallbacksObj, method_reportAGpsStatus,
+                        agps_status->type, agps_status->status);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
 AGpsCallbacks sAGpsCallbacks = {
     agps_status_callback,
+    create_thread_callback,
 };
 
+static void gps_ni_notify_callback(GpsNiNotification *notification)
+{
+    LOGD("gps_ni_notify_callback\n");
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jstring requestor_id = env->NewStringUTF(notification->requestor_id);
+    jstring text = env->NewStringUTF(notification->text);
+    jstring extras = env->NewStringUTF(notification->extras);
+
+    if (requestor_id && text && extras) {
+        env->CallVoidMethod(mCallbacksObj, method_reportNiNotification,
+            notification->notification_id, notification->ni_type,
+            notification->notify_flags, notification->timeout,
+            notification->default_response, requestor_id, text,
+            notification->requestor_id_encoding,
+            notification->text_encoding, extras);
+    } else {
+        LOGE("out of memory in gps_ni_notify_callback\n");
+    }
+
+    if (requestor_id)
+        env->DeleteLocalRef(requestor_id);
+    if (text)
+        env->DeleteLocalRef(text);
+    if (extras)
+        env->DeleteLocalRef(extras);
+    checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
 GpsNiCallbacks sGpsNiCallbacks = {
     gps_ni_notify_callback,
+    create_thread_callback,
 };
 
 static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env, jclass clazz) {
@@ -233,7 +209,7 @@
     method_reportStatus = env->GetMethodID(clazz, "reportStatus", "(I)V");
     method_reportSvStatus = env->GetMethodID(clazz, "reportSvStatus", "()V");
     method_reportAGpsStatus = env->GetMethodID(clazz, "reportAGpsStatus", "(II)V");
-    method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(IJ)V");
+    method_reportNmea = env->GetMethodID(clazz, "reportNmea", "(J)V");
     method_setEngineCapabilities = env->GetMethodID(clazz, "setEngineCapabilities", "(I)V");
     method_xtraDownloadRequest = env->GetMethodID(clazz, "xtraDownloadRequest", "()V");
     method_reportNiNotification = env->GetMethodID(clazz, "reportNiNotification", "(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
@@ -265,6 +241,12 @@
 
 static jboolean android_location_GpsLocationProvider_init(JNIEnv* env, jobject obj)
 {
+    LOGD("android_location_GpsLocationProvider_init obj: %p\n", obj);
+
+    // this must be set before calling into the HAL library
+    if (!mCallbacksObj)
+        mCallbacksObj = env->NewGlobalRef(obj);
+
     if (!sGpsInterface)
         sGpsInterface = get_gps_interface();
     if (!sGpsInterface || sGpsInterface->init(&sGpsCallbacks) != 0)
@@ -286,14 +268,6 @@
     return true;
 }
 
-static void android_location_GpsLocationProvider_disable(JNIEnv* env, jobject obj)
-{
-    pthread_mutex_lock(&sEventMutex);
-    sPendingCallbacks |= kDisableRequest;
-    pthread_cond_signal(&sEventCond);
-    pthread_mutex_unlock(&sEventMutex);
-}
-
 static void android_location_GpsLocationProvider_cleanup(JNIEnv* env, jobject obj)
 {
     sGpsInterface->cleanup();
@@ -321,90 +295,11 @@
     sGpsInterface->delete_aiding_data(flags);
 }
 
-static void android_location_GpsLocationProvider_wait_for_event(JNIEnv* env, jobject obj)
-{
-    pthread_mutex_lock(&sEventMutex);
-    while (sPendingCallbacks == 0) {
-        pthread_cond_wait(&sEventCond, &sEventMutex);
-    }
-
-    // copy and clear the callback flags
-    int pendingCallbacks = sPendingCallbacks;
-    sPendingCallbacks = 0;
-    int nmeaSentenceCount = mNmeaSentenceCount;
-    mNmeaSentenceCount = 0;
-    
-    // copy everything and unlock the mutex before calling into Java code to avoid the possibility
-    // of timeouts in the GPS engine.
-    if (pendingCallbacks & kLocation)
-        memcpy(&sGpsLocationCopy, &sGpsLocation, sizeof(sGpsLocationCopy));
-    if (pendingCallbacks & kStatus)
-        memcpy(&sGpsStatusCopy, &sGpsStatus, sizeof(sGpsStatusCopy));
-    if (pendingCallbacks & kSvStatus)
-        memcpy(&sGpsSvStatusCopy, &sGpsSvStatus, sizeof(sGpsSvStatusCopy));
-    if (pendingCallbacks & kAGpsStatus)
-        memcpy(&sAGpsStatusCopy, &sAGpsStatus, sizeof(sAGpsStatusCopy));
-    if (pendingCallbacks & kNmeaAvailable)
-        memcpy(&sNmeaBufferCopy, &sNmeaBuffer, nmeaSentenceCount * sizeof(sNmeaBuffer[0]));
-    if (pendingCallbacks & kNiNotification)
-        memcpy(&sGpsNiNotificationCopy, &sGpsNiNotification, sizeof(sGpsNiNotificationCopy));
-    pthread_mutex_unlock(&sEventMutex);   
-
-    if (pendingCallbacks & kLocation) {
-        env->CallVoidMethod(obj, method_reportLocation, sGpsLocationCopy.flags,
-                (jdouble)sGpsLocationCopy.latitude, (jdouble)sGpsLocationCopy.longitude,
-                (jdouble)sGpsLocationCopy.altitude,
-                (jfloat)sGpsLocationCopy.speed, (jfloat)sGpsLocationCopy.bearing,
-                (jfloat)sGpsLocationCopy.accuracy, (jlong)sGpsLocationCopy.timestamp);
-    }
-    if (pendingCallbacks & kStatus) {
-        env->CallVoidMethod(obj, method_reportStatus, sGpsStatusCopy.status);
-    }
-    if (pendingCallbacks & kSvStatus) {
-        env->CallVoidMethod(obj, method_reportSvStatus);
-    }
-    if (pendingCallbacks & kAGpsStatus) {
-        env->CallVoidMethod(obj, method_reportAGpsStatus, sAGpsStatusCopy.type, sAGpsStatusCopy.status);
-    }  
-    if (pendingCallbacks & kNmeaAvailable) {
-        for (int i = 0; i < nmeaSentenceCount; i++) {
-            env->CallVoidMethod(obj, method_reportNmea, i, sNmeaBuffer[i].timestamp);
-        }
-    }
-    if (pendingCallbacks & kXtraDownloadRequest) {
-        env->CallVoidMethod(obj, method_xtraDownloadRequest);
-    }
-    if (pendingCallbacks & kDisableRequest) {
-        // don't need to do anything - we are just poking so wait_for_event will return.
-    }
-    if (pendingCallbacks & kNiNotification) {
-       LOGD("android_location_GpsLocationProvider_wait_for_event: sent notification callback.");
-       jstring reqId = env->NewStringUTF(sGpsNiNotificationCopy.requestor_id);
-       jstring text = env->NewStringUTF(sGpsNiNotificationCopy.text);
-       jstring extras = env->NewStringUTF(sGpsNiNotificationCopy.extras);
-       env->CallVoidMethod(obj, method_reportNiNotification,
-             sGpsNiNotificationCopy.notification_id,
-             sGpsNiNotificationCopy.ni_type,
-             sGpsNiNotificationCopy.notify_flags,
-             sGpsNiNotificationCopy.timeout,
-             sGpsNiNotificationCopy.default_response,
-             reqId,
-             text,
-             sGpsNiNotificationCopy.requestor_id_encoding,
-             sGpsNiNotificationCopy.text_encoding,
-             extras
-       );
-    }
-    if (pendingCallbacks & kSetCapabilities) {
-        env->CallVoidMethod(obj, method_setEngineCapabilities, sEngineCapabilities);
-    }
-}
-
 static jint android_location_GpsLocationProvider_read_sv_status(JNIEnv* env, jobject obj,
         jintArray prnArray, jfloatArray snrArray, jfloatArray elevArray, jfloatArray azumArray,
         jintArray maskArray)
 {
-    // this should only be called from within a call to reportStatus, so we don't need to lock here
+    // this should only be called from within a call to reportSvStatus
 
     jint* prns = env->GetIntArrayElements(prnArray, 0);
     jfloat* snrs = env->GetFloatArrayElements(snrArray, 0);
@@ -412,16 +307,16 @@
     jfloat* azim = env->GetFloatArrayElements(azumArray, 0);
     jint* mask = env->GetIntArrayElements(maskArray, 0);
 
-    int num_svs = sGpsSvStatusCopy.num_svs;
+    int num_svs = sGpsSvStatus.num_svs;
     for (int i = 0; i < num_svs; i++) {
-        prns[i] = sGpsSvStatusCopy.sv_list[i].prn;
-        snrs[i] = sGpsSvStatusCopy.sv_list[i].snr;
-        elev[i] = sGpsSvStatusCopy.sv_list[i].elevation;
-        azim[i] = sGpsSvStatusCopy.sv_list[i].azimuth;
+        prns[i] = sGpsSvStatus.sv_list[i].prn;
+        snrs[i] = sGpsSvStatus.sv_list[i].snr;
+        elev[i] = sGpsSvStatus.sv_list[i].elevation;
+        azim[i] = sGpsSvStatus.sv_list[i].azimuth;
     }
-    mask[0] = sGpsSvStatusCopy.ephemeris_mask;
-    mask[1] = sGpsSvStatusCopy.almanac_mask;
-    mask[2] = sGpsSvStatusCopy.used_in_fix_mask;
+    mask[0] = sGpsSvStatus.ephemeris_mask;
+    mask[1] = sGpsSvStatus.almanac_mask;
+    mask[2] = sGpsSvStatus.used_in_fix_mask;
 
     env->ReleaseIntArrayElements(prnArray, prns, 0);
     env->ReleaseFloatArrayElements(snrArray, snrs, 0);
@@ -431,23 +326,21 @@
     return num_svs;
 }
 
-static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj, jint index, jbyteArray nmeaArray, jint buffer_size)
+static jint android_location_GpsLocationProvider_read_nmea(JNIEnv* env, jobject obj,
+                                            jbyteArray nmeaArray, jint buffer_size)
 {
-    // this should only be called from within a call to reportNmea, so we don't need to lock here
-
-    jbyte* nmea = env->GetByteArrayElements(nmeaArray, 0);
-
-    int length = strlen(sNmeaBufferCopy[index].nmea);
+    // this should only be called from within a call to reportNmea
+    jbyte* nmea = (jbyte *)env->GetPrimitiveArrayCritical(nmeaArray, 0);
+    int length = sNmeaStringLength;
     if (length > buffer_size)
         length = buffer_size;
-    memcpy(nmea, sNmeaBufferCopy[index].nmea, length);
-
-    env->ReleaseByteArrayElements(nmeaArray, nmea, 0);
+    memcpy(nmea, sNmeaString, length);
+    env->ReleasePrimitiveArrayCritical(nmeaArray, nmea, JNI_ABORT);
     return length;
 }
 
-static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobject obj, jlong time, 
-        jlong timeReference, jint uncertainty)
+static void android_location_GpsLocationProvider_inject_time(JNIEnv* env, jobject obj,
+        jlong time, jlong timeReference, jint uncertainty)
 {
     sGpsInterface->inject_time(time, timeReference, uncertainty);
 }
@@ -476,9 +369,9 @@
 static void android_location_GpsLocationProvider_inject_xtra_data(JNIEnv* env, jobject obj,
         jbyteArray data, jint length)
 {
-    jbyte* bytes = env->GetByteArrayElements(data, 0);
+    jbyte* bytes = (jbyte *)env->GetPrimitiveArrayCritical(data, 0);
     sGpsXtraInterface->inject_xtra_data((char *)bytes, length);
-    env->ReleaseByteArrayElements(data, bytes, 0);
+    env->ReleasePrimitiveArrayCritical(data, bytes, JNI_ABORT);
 }
 
 static void android_location_GpsLocationProvider_agps_data_conn_open(JNIEnv* env, jobject obj, jstring apn)
@@ -560,15 +453,13 @@
     {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
     {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported},
     {"native_init", "()Z", (void*)android_location_GpsLocationProvider_init},
-    {"native_disable", "()V", (void*)android_location_GpsLocationProvider_disable},
     {"native_cleanup", "()V", (void*)android_location_GpsLocationProvider_cleanup},
     {"native_set_position_mode", "(IIIII)Z", (void*)android_location_GpsLocationProvider_set_position_mode},
     {"native_start", "()Z", (void*)android_location_GpsLocationProvider_start},
     {"native_stop", "()Z", (void*)android_location_GpsLocationProvider_stop},
     {"native_delete_aiding_data", "(I)V", (void*)android_location_GpsLocationProvider_delete_aiding_data},
-    {"native_wait_for_event", "()V", (void*)android_location_GpsLocationProvider_wait_for_event},
     {"native_read_sv_status", "([I[F[F[F[I)I", (void*)android_location_GpsLocationProvider_read_sv_status},
-    {"native_read_nmea", "(I[BI)I", (void*)android_location_GpsLocationProvider_read_nmea},
+    {"native_read_nmea", "([BI)I", (void*)android_location_GpsLocationProvider_read_nmea},
     {"native_inject_time", "(JJI)V", (void*)android_location_GpsLocationProvider_inject_time},
     {"native_inject_location", "(DDF)V", (void*)android_location_GpsLocationProvider_inject_location},
     {"native_supports_xtra", "()Z", (void*)android_location_GpsLocationProvider_supports_xtra},