Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e9f61b65 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Drop invalid locations" into main

parents d98c52f2 cbadbf45
Loading
Loading
Loading
Loading
+70 −8
Original line number Diff line number Diff line
@@ -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;

@@ -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.
@@ -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);
@@ -114,6 +175,7 @@ public final class LocationResult implements Parcelable {
                    throw new IllegalArgumentException(
                            "incorrectly ordered location at index " + i + ": " + mLocations);
                }
            }
            prevElapsedRealtimeNs = location.getElapsedRealtimeNanos();
        }

+7 −0
Original line number Diff line number Diff line
@@ -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"
}
+11 −2
Original line number Diff line number Diff line
@@ -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;
@@ -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);
@@ -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;
+9 −19
Original line number Diff line number Diff line
@@ -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;
@@ -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;
                                }
@@ -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);
@@ -2626,7 +2616,7 @@ public class LocationProviderManager extends
                return location;
            });
        }
        return processed;
        return locationResult;
    }

    @GuardedBy("mMultiplexerLock")
+6 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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