Enforce the minTime parameter in LocationManager#requestLocationUpdates

There is a long history in Android, on both GED and non GED devices
of GPS providers ignoring the minTime parameter making location updates
every second. The problem is usually poor GPS drivers that claim to
do scheduling but then do not.

By making the minTime parameter strict (instead of a hint) we can add
a CTS test to ensure that udpates to not occur too frequently. I believe
this is the desired behavior from apps. If apps want to take advantage
of more frequent updates when another application asks for those updates
then it can use the passive provider.

The CTS test for GPS has already been submitted (as part of CTS Verifier).

Bug: 6424983
Change-Id: I163b9e44ea7ab71530b86fc2282614e0150e90f1
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 4582d67..1e707b2 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -105,6 +105,12 @@
     private static final String INSTALL_LOCATION_PROVIDER =
         android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
 
+    // Location Providers may sometimes deliver location updates
+    // slightly faster that requested - provide grace period so
+    // we don't unnecessarily filter events that are otherwise on
+    // time
+    private static final int MAX_PROVIDER_SCHEDULING_JITTER = 100;
+
     // Set of providers that are explicitly enabled
     private final Set<String> mEnabledProviders = new HashSet<String>();
 
@@ -194,8 +200,9 @@
         final PendingIntent mPendingIntent;
         final Object mKey;
         final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
+
         int mPendingBroadcasts;
-        String requiredPermissions;
+        String mRequiredPermissions;
 
         Receiver(ILocationListener listener) {
             mListener = listener;
@@ -286,7 +293,7 @@
                         // synchronize to ensure incrementPendingBroadcastsLocked()
                         // is called before decrementPendingBroadcasts()
                         mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
-                                requiredPermissions);
+                                mRequiredPermissions);
                         // call this after broadcasting so we do not increment
                         // if we throw an exeption.
                         incrementPendingBroadcastsLocked();
@@ -322,7 +329,7 @@
                         // synchronize to ensure incrementPendingBroadcastsLocked()
                         // is called before decrementPendingBroadcasts()
                         mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
-                                requiredPermissions);
+                                mRequiredPermissions);
                         // call this after broadcasting so we do not increment
                         // if we throw an exeption.
                         incrementPendingBroadcastsLocked();
@@ -362,7 +369,7 @@
                         // synchronize to ensure incrementPendingBroadcastsLocked()
                         // is called before decrementPendingBroadcasts()
                         mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
-                                requiredPermissions);
+                                mRequiredPermissions);
                         // call this after broadcasting so we do not increment
                         // if we throw an exeption.
                         incrementPendingBroadcastsLocked();
@@ -374,6 +381,7 @@
             return true;
         }
 
+        @Override
         public void binderDied() {
             if (LOCAL_LOGV) {
                 Slog.v(TAG, "Location listener died");
@@ -1026,7 +1034,7 @@
                     + Integer.toHexString(System.identityHashCode(this))
                     + " mProvider: " + mProvider + " mUid: " + mUid + "}";
         }
-        
+
         void dump(PrintWriter pw, String prefix) {
             pw.println(prefix + this);
             pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver);
@@ -1155,10 +1163,11 @@
 
         LocationProviderInterface p = mProvidersByName.get(provider);
         if (p == null) {
-            throw new IllegalArgumentException("provider=" + provider);
+            throw new IllegalArgumentException("requested provider " + provider +
+                    " doesn't exisit");
         }
-        receiver.requiredPermissions = checkPermissionsSafe(provider,
-                receiver.requiredPermissions);
+        receiver.mRequiredPermissions = checkPermissionsSafe(provider,
+                receiver.mRequiredPermissions);
 
         // so wakelock calls will succeed
         final int callingPid = Binder.getCallingPid();
@@ -1752,9 +1761,9 @@
             return true;
         }
 
-        // Don't broadcast same location again regardless of condition
-        // TODO - we should probably still rebroadcast if user explicitly sets a minTime > 0
-        if (loc.getTime() == lastLoc.getTime()) {
+        // Check whether sufficient time has passed
+        long minTime = record.mMinTime;
+        if (loc.getTime() - lastLoc.getTime() < minTime - MAX_PROVIDER_SCHEDULING_JITTER) {
             return false;
         }