Merge "Improve Location dump Timestamps" into qt-dev
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 3410d8d..44fc45e 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -88,6 +88,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
+import android.util.TimeUtils;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageMonitor;
@@ -3567,6 +3568,10 @@
                 return;
             }
             pw.println("Current Location Manager state:");
+            pw.print("  Current System Time: "
+                    + TimeUtils.logTimeOfDay(System.currentTimeMillis()));
+            pw.println(", Current Elapsed Time: "
+                    + TimeUtils.formatDuration(SystemClock.elapsedRealtime()));
             pw.println("  Current user: " + mCurrentUserId + " " + Arrays.toString(
                     mCurrentUserProfiles));
             pw.println("  Location mode: " + isLocationEnabled());
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 96fc6ec..ff0af13 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -66,6 +66,7 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.StatsLog;
+import android.util.TimeUtils;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IBatteryStats;
@@ -332,9 +333,16 @@
     // true if low power mode for the GNSS chipset is part of the latest request.
     private boolean mLowPowerMode = false;
 
-    // true if we started navigation
+    // true if we started navigation in the HAL, only change value of this in setStarted
     private boolean mStarted;
 
+    // for logging of latest change, and warning of ongoing location after a stop
+    private long mStartedChangedElapsedRealtime;
+
+    // threshold for delay in GNSS engine turning off before warning & error
+    private static final long LOCATION_OFF_DELAY_THRESHOLD_WARN_MILLIS = 2 * 1000;
+    private static final long LOCATION_OFF_DELAY_THRESHOLD_ERROR_MILLIS = 15 * 1000;
+
     // capabilities reported through the top level IGnssCallback.hal
     private volatile int mTopHalCapabilities;
 
@@ -1192,7 +1200,7 @@
             if (DEBUG) Log.d(TAG, "startNavigating");
             mTimeToFirstFix = 0;
             mLastFixTime = 0;
-            mStarted = true;
+            setStarted(true);
             mPositionMode = GPS_POSITION_MODE_STANDALONE;
             // Notify about suppressed output, if speed limit was previously exceeded.
             // Elsewhere, we check again with every speed output reported.
@@ -1230,12 +1238,12 @@
             mLowPowerMode = mProviderRequest.lowPowerMode;
             if (!setPositionMode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
                     interval, 0, 0, mLowPowerMode)) {
-                mStarted = false;
+                setStarted(false);
                 Log.e(TAG, "set_position_mode failed in startNavigating()");
                 return;
             }
             if (!native_start()) {
-                mStarted = false;
+                setStarted(false);
                 Log.e(TAG, "native_start failed in startNavigating()");
                 return;
             }
@@ -1258,7 +1266,7 @@
     private void stopNavigating() {
         if (DEBUG) Log.d(TAG, "stopNavigating");
         if (mStarted) {
-            mStarted = false;
+            setStarted(false);
             native_stop();
             mLastFixTime = 0;
             // native_stop() may reset the position mode in hardware.
@@ -1270,6 +1278,13 @@
         }
     }
 
+    private void setStarted(boolean started) {
+        if (mStarted != started) {
+            mStarted = started;
+            mStartedChangedElapsedRealtime = SystemClock.elapsedRealtime();
+        }
+    }
+
     private void hibernate() {
         // stop GPS until our next fix interval arrives
         stopNavigating();
@@ -1319,6 +1334,21 @@
                     mGnssMetrics.logMissedReports(mFixInterval, timeBetweenFixes);
                 }
             }
+        } else {
+            // Warn or error about long delayed GNSS engine shutdown as this generally wastes
+            // power and sends location when not expected.
+            long locationAfterStartedFalseMillis =
+                    SystemClock.elapsedRealtime() - mStartedChangedElapsedRealtime;
+            if (locationAfterStartedFalseMillis > LOCATION_OFF_DELAY_THRESHOLD_WARN_MILLIS) {
+                String logMessage = "Unexpected GNSS Location report "
+                        + TimeUtils.formatDuration(locationAfterStartedFalseMillis)
+                        + " after location turned off";
+                if (locationAfterStartedFalseMillis > LOCATION_OFF_DELAY_THRESHOLD_ERROR_MILLIS) {
+                    Log.e(TAG, logMessage);
+                } else {
+                    Log.w(TAG, logMessage);
+                }
+            }
         }
 
         mLastFixTime = SystemClock.elapsedRealtime();
@@ -1538,7 +1568,7 @@
 
     private void restartLocationRequest() {
         if (DEBUG) Log.d(TAG, "restartLocationRequest");
-        mStarted = false;
+        setStarted(false);
         updateRequirements();
     }
 
@@ -2152,7 +2182,10 @@
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         StringBuilder s = new StringBuilder();
-        s.append("  mStarted=").append(mStarted).append('\n');
+        s.append("  mStarted=").append(mStarted).append("   (changed ");
+        TimeUtils.formatDuration(SystemClock.elapsedRealtime()
+                - mStartedChangedElapsedRealtime, s);
+        s.append(" ago)").append('\n');
         s.append("  mFixInterval=").append(mFixInterval).append('\n');
         s.append("  mLowPowerMode=").append(mLowPowerMode).append('\n');
         s.append("  mGnssMeasurementsProvider.isRegistered()=")