Loading location/java/android/location/LocationResult.java +70 −8 Original line number Diff line number Diff line Loading @@ -19,8 +19,11 @@ package android.location; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.location.flags.Flags; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; import android.util.Log; import com.android.internal.util.Preconditions; Loading @@ -37,6 +40,23 @@ import java.util.function.Predicate; * @hide */ public final class LocationResult implements Parcelable { private static final String TAG = "LocationResult"; // maximum reasonable accuracy, somewhat arbitrarily chosen. this is a very high upper limit, it // could likely be lower, but we only want to throw out really absurd values. private static final float MAX_ACCURACY_M = 1000000; // maximum reasonable speed we expect a device to travel at is currently mach 1 (top speed of // current fastest private jet). Higher speed than the value is considered as a malfunction // than a correct reading. private static final float MAX_SPEED_MPS = 343; /** Exception representing an invalid location within a {@link LocationResult}. */ public static class BadLocationException extends Exception { public BadLocationException(String message) { super(message); } } /** * Creates a new LocationResult from the given locations, making a copy of each location. Loading Loading @@ -101,11 +121,52 @@ public final class LocationResult implements Parcelable { * * @hide */ public @NonNull LocationResult validate() { public @NonNull LocationResult validate() throws BadLocationException { long prevElapsedRealtimeNs = 0; final int size = mLocations.size(); for (int i = 0; i < size; ++i) { Location location = mLocations.get(i); if (Flags.locationValidation()) { if (location.getLatitude() < -90.0 || location.getLatitude() > 90.0 || location.getLongitude() < -180.0 || location.getLongitude() > 180.0 || Double.isNaN(location.getLatitude()) || Double.isNaN(location.getLongitude())) { throw new BadLocationException("location must have valid lat/lng"); } if (!location.hasAccuracy()) { throw new BadLocationException("location must have accuracy"); } if (location.getAccuracy() < 0 || location.getAccuracy() > MAX_ACCURACY_M) { throw new BadLocationException("location must have reasonable accuracy"); } if (location.getTime() < 0) { throw new BadLocationException("location must have valid time"); } if (prevElapsedRealtimeNs > location.getElapsedRealtimeNanos()) { throw new BadLocationException( "location must have valid monotonically increasing realtime"); } if (location.getElapsedRealtimeNanos() > SystemClock.elapsedRealtimeNanos()) { throw new BadLocationException("location must not have realtime in the future"); } if (!location.isMock()) { if (location.getProvider() == null) { throw new BadLocationException("location must have valid provider"); } if (location.getLatitude() == 0 && location.getLongitude() == 0) { throw new BadLocationException("location must not be at 0,0"); } } if (location.hasSpeed() && (location.getSpeed() < 0 || location.getSpeed() > MAX_SPEED_MPS)) { Log.w(TAG, "removed bad location speed: " + location.getSpeed()); location.removeSpeed(); } } else { if (!location.isComplete()) { throw new IllegalArgumentException( "incomplete location at index " + i + ": " + mLocations); Loading @@ -114,6 +175,7 @@ public final class LocationResult implements Parcelable { throw new IllegalArgumentException( "incorrectly ordered location at index " + i + ": " + mLocations); } } prevElapsedRealtimeNs = location.getElapsedRealtimeNanos(); } Loading location/java/android/location/flags/gnss.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -27,3 +27,10 @@ flag { description: "Flag for releasing SUPL connection on timeout" bug: "315024652" } flag { name: "location_validation" namespace: "location" description: "Flag for location validation" bug: "314328533" } services/core/java/com/android/server/location/gnss/GnssLocationProvider.java +11 −2 Original line number Diff line number Diff line Loading @@ -67,6 +67,7 @@ import android.location.LocationListener; import android.location.LocationManager; import android.location.LocationRequest; import android.location.LocationResult; import android.location.LocationResult.BadLocationException; import android.location.flags.Flags; import android.location.provider.ProviderProperties; import android.location.provider.ProviderRequest; Loading Loading @@ -1380,7 +1381,11 @@ public class GnssLocationProvider extends AbstractLocationProvider implements location.setExtras(mLocationExtras.getBundle()); try { reportLocation(LocationResult.wrap(location).validate()); } catch (BadLocationException e) { throw new IllegalArgumentException(e); } if (mStarted) { mGnssMetrics.logReceivedLocationStatus(hasLatLong); Loading Loading @@ -1751,7 +1756,11 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } } try { reportLocation(LocationResult.wrap(locations).validate()); } catch (BadLocationException e) { throw new IllegalArgumentException(e); } } Runnable[] listeners; Loading services/core/java/com/android/server/location/provider/LocationProviderManager.java +9 −19 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ import android.location.LocationManagerInternal; import android.location.LocationManagerInternal.ProviderEnabledListener; import android.location.LocationRequest; import android.location.LocationResult; import android.location.LocationResult.BadLocationException; import android.location.altitude.AltitudeConverter; import android.location.provider.IProviderRequestListener; import android.location.provider.ProviderProperties; Loading Loading @@ -910,7 +911,8 @@ public class LocationProviderManager extends < getRequest().getMinUpdateIntervalMillis() - maxJitterMs) { if (D) { Log.v(TAG, mName + " provider registration " + getIdentity() + " dropped delivery - too fast"); + " dropped delivery - too fast (deltaMs=" + deltaMs + ")."); } return false; } Loading Loading @@ -2574,29 +2576,17 @@ public class LocationProviderManager extends @GuardedBy("mMultiplexerLock") @Nullable private LocationResult processReportedLocation(LocationResult locationResult) { LocationResult processed = locationResult.filter(location -> { if (!location.isMock()) { if (location.getLatitude() == 0 && location.getLongitude() == 0) { Log.e(TAG, "blocking 0,0 location from " + mName + " provider"); return false; } } if (!location.isComplete()) { Log.e(TAG, "blocking incomplete location from " + mName + " provider"); return false; } return true; }); if (processed == null) { try { locationResult.validate(); } catch (BadLocationException e) { Log.e(TAG, "Dropping invalid locations: " + e); return null; } // Attempt to add a missing MSL altitude on behalf of the provider. if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_LOCATION, "enable_location_provider_manager_msl", true)) { return processed.map(location -> { return locationResult.map(location -> { if (!location.hasMslAltitude() && location.hasAltitude()) { try { Location locationCopy = new Location(location); Loading Loading @@ -2626,7 +2616,7 @@ public class LocationProviderManager extends return location; }); } return processed; return locationResult; } @GuardedBy("mMultiplexerLock") Loading services/core/java/com/android/server/location/provider/MockLocationProvider.java +6 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; import android.annotation.Nullable; import android.location.Location; import android.location.LocationResult; import android.location.LocationResult.BadLocationException; import android.location.provider.ProviderProperties; import android.location.provider.ProviderRequest; import android.location.util.identity.CallerIdentity; Loading Loading @@ -55,7 +56,11 @@ public class MockLocationProvider extends AbstractLocationProvider { Location location = new Location(l); location.setIsFromMockProvider(true); mLocation = location; try { reportLocation(LocationResult.wrap(location).validate()); } catch (BadLocationException e) { throw new IllegalArgumentException(e); } } @Override Loading Loading
location/java/android/location/LocationResult.java +70 −8 Original line number Diff line number Diff line Loading @@ -19,8 +19,11 @@ package android.location; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.location.flags.Flags; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; import android.util.Log; import com.android.internal.util.Preconditions; Loading @@ -37,6 +40,23 @@ import java.util.function.Predicate; * @hide */ public final class LocationResult implements Parcelable { private static final String TAG = "LocationResult"; // maximum reasonable accuracy, somewhat arbitrarily chosen. this is a very high upper limit, it // could likely be lower, but we only want to throw out really absurd values. private static final float MAX_ACCURACY_M = 1000000; // maximum reasonable speed we expect a device to travel at is currently mach 1 (top speed of // current fastest private jet). Higher speed than the value is considered as a malfunction // than a correct reading. private static final float MAX_SPEED_MPS = 343; /** Exception representing an invalid location within a {@link LocationResult}. */ public static class BadLocationException extends Exception { public BadLocationException(String message) { super(message); } } /** * Creates a new LocationResult from the given locations, making a copy of each location. Loading Loading @@ -101,11 +121,52 @@ public final class LocationResult implements Parcelable { * * @hide */ public @NonNull LocationResult validate() { public @NonNull LocationResult validate() throws BadLocationException { long prevElapsedRealtimeNs = 0; final int size = mLocations.size(); for (int i = 0; i < size; ++i) { Location location = mLocations.get(i); if (Flags.locationValidation()) { if (location.getLatitude() < -90.0 || location.getLatitude() > 90.0 || location.getLongitude() < -180.0 || location.getLongitude() > 180.0 || Double.isNaN(location.getLatitude()) || Double.isNaN(location.getLongitude())) { throw new BadLocationException("location must have valid lat/lng"); } if (!location.hasAccuracy()) { throw new BadLocationException("location must have accuracy"); } if (location.getAccuracy() < 0 || location.getAccuracy() > MAX_ACCURACY_M) { throw new BadLocationException("location must have reasonable accuracy"); } if (location.getTime() < 0) { throw new BadLocationException("location must have valid time"); } if (prevElapsedRealtimeNs > location.getElapsedRealtimeNanos()) { throw new BadLocationException( "location must have valid monotonically increasing realtime"); } if (location.getElapsedRealtimeNanos() > SystemClock.elapsedRealtimeNanos()) { throw new BadLocationException("location must not have realtime in the future"); } if (!location.isMock()) { if (location.getProvider() == null) { throw new BadLocationException("location must have valid provider"); } if (location.getLatitude() == 0 && location.getLongitude() == 0) { throw new BadLocationException("location must not be at 0,0"); } } if (location.hasSpeed() && (location.getSpeed() < 0 || location.getSpeed() > MAX_SPEED_MPS)) { Log.w(TAG, "removed bad location speed: " + location.getSpeed()); location.removeSpeed(); } } else { if (!location.isComplete()) { throw new IllegalArgumentException( "incomplete location at index " + i + ": " + mLocations); Loading @@ -114,6 +175,7 @@ public final class LocationResult implements Parcelable { throw new IllegalArgumentException( "incorrectly ordered location at index " + i + ": " + mLocations); } } prevElapsedRealtimeNs = location.getElapsedRealtimeNanos(); } Loading
location/java/android/location/flags/gnss.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -27,3 +27,10 @@ flag { description: "Flag for releasing SUPL connection on timeout" bug: "315024652" } flag { name: "location_validation" namespace: "location" description: "Flag for location validation" bug: "314328533" }
services/core/java/com/android/server/location/gnss/GnssLocationProvider.java +11 −2 Original line number Diff line number Diff line Loading @@ -67,6 +67,7 @@ import android.location.LocationListener; import android.location.LocationManager; import android.location.LocationRequest; import android.location.LocationResult; import android.location.LocationResult.BadLocationException; import android.location.flags.Flags; import android.location.provider.ProviderProperties; import android.location.provider.ProviderRequest; Loading Loading @@ -1380,7 +1381,11 @@ public class GnssLocationProvider extends AbstractLocationProvider implements location.setExtras(mLocationExtras.getBundle()); try { reportLocation(LocationResult.wrap(location).validate()); } catch (BadLocationException e) { throw new IllegalArgumentException(e); } if (mStarted) { mGnssMetrics.logReceivedLocationStatus(hasLatLong); Loading Loading @@ -1751,7 +1756,11 @@ public class GnssLocationProvider extends AbstractLocationProvider implements } } try { reportLocation(LocationResult.wrap(locations).validate()); } catch (BadLocationException e) { throw new IllegalArgumentException(e); } } Runnable[] listeners; Loading
services/core/java/com/android/server/location/provider/LocationProviderManager.java +9 −19 Original line number Diff line number Diff line Loading @@ -64,6 +64,7 @@ import android.location.LocationManagerInternal; import android.location.LocationManagerInternal.ProviderEnabledListener; import android.location.LocationRequest; import android.location.LocationResult; import android.location.LocationResult.BadLocationException; import android.location.altitude.AltitudeConverter; import android.location.provider.IProviderRequestListener; import android.location.provider.ProviderProperties; Loading Loading @@ -910,7 +911,8 @@ public class LocationProviderManager extends < getRequest().getMinUpdateIntervalMillis() - maxJitterMs) { if (D) { Log.v(TAG, mName + " provider registration " + getIdentity() + " dropped delivery - too fast"); + " dropped delivery - too fast (deltaMs=" + deltaMs + ")."); } return false; } Loading Loading @@ -2574,29 +2576,17 @@ public class LocationProviderManager extends @GuardedBy("mMultiplexerLock") @Nullable private LocationResult processReportedLocation(LocationResult locationResult) { LocationResult processed = locationResult.filter(location -> { if (!location.isMock()) { if (location.getLatitude() == 0 && location.getLongitude() == 0) { Log.e(TAG, "blocking 0,0 location from " + mName + " provider"); return false; } } if (!location.isComplete()) { Log.e(TAG, "blocking incomplete location from " + mName + " provider"); return false; } return true; }); if (processed == null) { try { locationResult.validate(); } catch (BadLocationException e) { Log.e(TAG, "Dropping invalid locations: " + e); return null; } // Attempt to add a missing MSL altitude on behalf of the provider. if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_LOCATION, "enable_location_provider_manager_msl", true)) { return processed.map(location -> { return locationResult.map(location -> { if (!location.hasMslAltitude() && location.hasAltitude()) { try { Location locationCopy = new Location(location); Loading Loading @@ -2626,7 +2616,7 @@ public class LocationProviderManager extends return location; }); } return processed; return locationResult; } @GuardedBy("mMultiplexerLock") Loading
services/core/java/com/android/server/location/provider/MockLocationProvider.java +6 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR; import android.annotation.Nullable; import android.location.Location; import android.location.LocationResult; import android.location.LocationResult.BadLocationException; import android.location.provider.ProviderProperties; import android.location.provider.ProviderRequest; import android.location.util.identity.CallerIdentity; Loading Loading @@ -55,7 +56,11 @@ public class MockLocationProvider extends AbstractLocationProvider { Location location = new Location(l); location.setIsFromMockProvider(true); mLocation = location; try { reportLocation(LocationResult.wrap(location).validate()); } catch (BadLocationException e) { throw new IllegalArgumentException(e); } } @Override Loading