Merge "location: dump LocationProvider internal state"
diff --git a/core/jni/android_location_GpsLocationProvider.cpp b/core/jni/android_location_GpsLocationProvider.cpp
index f845878..a3be309 100755
--- a/core/jni/android_location_GpsLocationProvider.cpp
+++ b/core/jni/android_location_GpsLocationProvider.cpp
@@ -42,6 +42,7 @@
 static const GpsXtraInterface* sGpsXtraInterface = NULL;
 static const AGpsInterface* sAGpsInterface = NULL;
 static const GpsNiInterface* sGpsNiInterface = NULL;
+static const GpsDebugInterface* sGpsDebugInterface = NULL;
 
 // data written to by GPS callbacks
 static GpsLocation  sGpsLocation;
@@ -57,7 +58,7 @@
     GpsUtcTime  timestamp;
     char        nmea[NMEA_SENTENCE_LENGTH];
 };
-static NmeaSentence sNmeaBuffer[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
@@ -66,7 +67,7 @@
 static GpsStatus    sGpsStatusCopy;
 static GpsSvStatus  sGpsSvStatusCopy;
 static AGpsStatus   sAGpsStatusCopy;
-static NmeaSentence sNmeaBufferCopy[NMEA_SENTENCE_LENGTH];
+static NmeaSentence sNmeaBufferCopy[NMEA_SENTENCE_COUNT];
 static GpsNiNotification  sGpsNiNotificationCopy;
 
 enum CallbackType {
@@ -226,6 +227,9 @@
     if (sGpsNiInterface)
        sGpsNiInterface->init(&sGpsNiCallbacks);
 
+    if (!sGpsDebugInterface)
+       sGpsDebugInterface = (const GpsDebugInterface*)sGpsInterface->get_extension(GPS_DEBUG_INTERFACE);
+
     return true;
 }
 
@@ -472,11 +476,26 @@
 static void android_location_GpsLocationProvider_send_ni_response(JNIEnv* env, jobject obj,
       jint notifId, jint response)
 {
-   if (!sGpsNiInterface)
-      sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
-   if (sGpsNiInterface) {
-      sGpsNiInterface->respond(notifId, response);
-   }
+    if (!sGpsNiInterface) {
+        sGpsNiInterface = (const GpsNiInterface*)sGpsInterface->get_extension(GPS_NI_INTERFACE);
+    }
+    if (sGpsNiInterface) {
+        sGpsNiInterface->respond(notifId, response);
+    }
+}
+
+static jstring android_location_GpsLocationProvider_get_internal_state(JNIEnv* env, jobject obj)
+{
+    jstring result = NULL;
+    if (sGpsDebugInterface) {
+        const size_t maxLength = 2047;
+        char buffer[maxLength+1];
+        size_t length = sGpsDebugInterface->get_internal_state(buffer, maxLength);
+        if (length > maxLength) length = maxLength;
+        buffer[length] = 0;
+        result = env->NewStringUTF(buffer);
+    }
+    return result;
 }
 
 static JNINativeMethod sMethods[] = {
@@ -501,6 +520,7 @@
     {"native_agps_data_conn_failed", "()V", (void*)android_location_GpsLocationProvider_agps_data_conn_failed},
     {"native_set_agps_server", "(ILjava/lang/String;I)V", (void*)android_location_GpsLocationProvider_set_agps_server},
     {"native_send_ni_response", "(II)V", (void*)android_location_GpsLocationProvider_send_ni_response},
+    {"native_get_internal_state", "()Ljava/lang/String;", (void*)android_location_GpsLocationProvider_get_internal_state},
 };
 
 int register_android_location_GpsLocationProvider(JNIEnv* env)
diff --git a/location/java/android/location/ILocationProvider.aidl b/location/java/android/location/ILocationProvider.aidl
index 5529b11..97b283c 100644
--- a/location/java/android/location/ILocationProvider.aidl
+++ b/location/java/android/location/ILocationProvider.aidl
@@ -39,6 +39,7 @@
     void disable();
     int getStatus(out Bundle extras);
     long getStatusUpdateTime();
+    String getInternalState();
     void enableLocationTracking(boolean enable);
     void setMinTime(long minTime);
     void updateNetworkState(int state, in NetworkInfo info);
diff --git a/location/java/android/location/LocationProviderInterface.java b/location/java/android/location/LocationProviderInterface.java
index 98beffe..5ffe15c 100644
--- a/location/java/android/location/LocationProviderInterface.java
+++ b/location/java/android/location/LocationProviderInterface.java
@@ -42,6 +42,7 @@
     int getStatus(Bundle extras);
     long getStatusUpdateTime();
     void enableLocationTracking(boolean enable);
+    String getInternalState();
     void setMinTime(long minTime);
     void updateNetworkState(int state, NetworkInfo info);
     void updateLocation(Location location);
diff --git a/location/java/android/location/provider/LocationProvider.java b/location/java/android/location/provider/LocationProvider.java
index 4163def..56cfb33 100644
--- a/location/java/android/location/provider/LocationProvider.java
+++ b/location/java/android/location/provider/LocationProvider.java
@@ -95,6 +95,10 @@
             return LocationProvider.this.onGetStatusUpdateTime();
         }
 
+        public String getInternalState() {
+            return LocationProvider.this.onGetInternalState();
+        }
+
         public void enableLocationTracking(boolean enable) {
             LocationProvider.this.onEnableLocationTracking(enable);
         }
@@ -267,6 +271,13 @@
     public abstract long onGetStatusUpdateTime();
 
     /**
+     * Returns debugging information about the location provider.
+     *
+     * @return string describing the internal state of the location provider, or null.
+     */
+    public abstract String onGetInternalState();
+
+    /**
      * Notifies the location provider that clients are listening for locations.
      * Called with enable set to true when the first client is added and
      * called with enable set to false when the last client is removed.
diff --git a/location/java/com/android/internal/location/GpsLocationProvider.java b/location/java/com/android/internal/location/GpsLocationProvider.java
index 90b50cc..44a5a6b 100755
--- a/location/java/com/android/internal/location/GpsLocationProvider.java
+++ b/location/java/com/android/internal/location/GpsLocationProvider.java
@@ -633,6 +633,10 @@
         }
     }
 
+    public String getInternalState() {
+        return native_get_internal_state();
+    }
+
     private final class Listener implements IBinder.DeathRecipient {
         final IGpsStatusListener mListener;
         
@@ -1391,12 +1395,15 @@
     private native int native_read_nmea(int index, byte[] buffer, int bufferSize);
     private native void native_inject_location(double latitude, double longitude, float accuracy);
 
-    // XTRA Support    
+    // XTRA Support
     private native void native_inject_time(long time, long timeReference, int uncertainty);
     private native boolean native_supports_xtra();
     private native void native_inject_xtra_data(byte[] data, int length);
 
-    // AGPS Support    
+    // DEBUG Support
+    private native String native_get_internal_state();
+
+    // AGPS Support
     private native void native_agps_data_conn_open(String apn);
     private native void native_agps_data_conn_closed();
     private native void native_agps_data_conn_failed();
diff --git a/location/java/com/android/internal/location/LocationProviderProxy.java b/location/java/com/android/internal/location/LocationProviderProxy.java
index abb90b7..31ec09a 100644
--- a/location/java/com/android/internal/location/LocationProviderProxy.java
+++ b/location/java/com/android/internal/location/LocationProviderProxy.java
@@ -266,6 +266,15 @@
         return 0;
      }
 
+    public String getInternalState() {
+        try {
+            return mProvider.getInternalState();
+        } catch (RemoteException e) {
+            Log.e(TAG, "getInternalState failed", e);
+            return null;
+        }
+    }
+
     public boolean isLocationTracking() {
         return mLocationTracking;
     }
diff --git a/location/java/com/android/internal/location/MockProvider.java b/location/java/com/android/internal/location/MockProvider.java
index bc1893e..d912740 100644
--- a/location/java/com/android/internal/location/MockProvider.java
+++ b/location/java/com/android/internal/location/MockProvider.java
@@ -168,6 +168,10 @@
         mStatusUpdateTime = 0;
     }
 
+    public String getInternalState() {
+        return null;
+    }
+
     public void enableLocationTracking(boolean enable) {
     }
 
diff --git a/location/java/com/android/internal/location/PassiveProvider.java b/location/java/com/android/internal/location/PassiveProvider.java
index 7eb711d..ab90937 100644
--- a/location/java/com/android/internal/location/PassiveProvider.java
+++ b/location/java/com/android/internal/location/PassiveProvider.java
@@ -106,6 +106,10 @@
         return -1;
     }
 
+    public String getInternalState() {
+        return null;
+    }
+
     public void enableLocationTracking(boolean enable) {
         mTracking = enable;
     }
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 8d00deb..7aa092a 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -765,7 +765,9 @@
             pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance);
             pw.println(prefix + "mUid=" + mUid);
             pw.println(prefix + "mLastFixBroadcast:");
-            mLastFixBroadcast.dump(new PrintWriterPrinter(pw), prefix + "  ");
+            if (mLastFixBroadcast != null) {
+                mLastFixBroadcast.dump(new PrintWriterPrinter(pw), prefix + "  ");
+            }
             pw.println(prefix + "mLastStatusBroadcast=" + mLastStatusBroadcast);
         }
     }
@@ -1954,6 +1956,13 @@
                     i.getValue().dump(pw, "      ");
                 }
             }
+            for (LocationProviderInterface provider: mProviders) {
+                String state = provider.getInternalState();
+                if (state != null) {
+                    pw.println(provider.getName() + " Internal State:");
+                    pw.write(state);
+                }
+            }
         }
     }
 }