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

Commit 09016ab4 authored by Victoria Lease's avatar Victoria Lease
Browse files

Do not use passive GPS data for COARSE only apps.

FusionEngine now attaches a secondary location that has never seen
GPS data to its result. LocationFudger uses the GPS-less location so
that COARSE apps never see data from the GPS provider.

When the previous location is updated, the previous GPS-less location
is carried over if the location update was GPS-only.

Additionally, apps without FINE permission are not notified when GPS
location changes, and any attempt to use GPS_PROVIDER without FINE
permission is met by a stern SecurityException.

Bug: 7153659
Change-Id: I12f26725782892038ce1133561e1908d91378a4a
parent 537d47f5
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
@@ -59,6 +59,16 @@ public class Location implements Parcelable {
     */
    public static final int FORMAT_SECONDS = 2;

    /**
     * @hide
     */
    public static final String EXTRA_COARSE_LOCATION = "coarseLocation";

    /**
     * @hide
     */
    public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation";

    private String mProvider;
    private long mTime = 0;
    private long mElapsedRealtimeNano = 0;
@@ -897,4 +907,36 @@ public class Location implements Parcelable {
        parcel.writeFloat(mAccuracy);
        parcel.writeBundle(mExtras);
    }

    /**
     * Returns one of the optional extra {@link Location}s that can be attached
     * to this Location.
     *
     * @param key the key associated with the desired extra Location
     * @return the extra Location, or null if unavailable
     * @hide
     */
    public Location getExtraLocation(String key) {
        if (mExtras != null) {
            Parcelable value = mExtras.getParcelable(key);
            if (value instanceof Location) {
                return (Location) value;
            }
        }
        return null;
    }

    /**
     * Attaches an extra {@link Location} to this Location.
     *
     * @param key the key associated with the Location extra
     * @param location the Location to attach
     * @hide
     */
    public void setExtraLocation(String key, Location value) {
        if (mExtras == null) {
            mExtras = new Bundle();
        }
        mExtras.putParcelable(key, value);
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -144,7 +144,7 @@ public final class LocationRequest implements Parcelable {
    private int mNumUpdates = Integer.MAX_VALUE;  // no expiry
    private float mSmallestDisplacement = 0.0f;    // meters

    private String mProvider = null;  // for deprecated API's that explicitly request a provider
    private String mProvider = LocationManager.FUSED_PROVIDER;  // for deprecated APIs that explicitly request a provider

    /**
     * Create a location request with default parameters.
+4 −0
Original line number Diff line number Diff line
@@ -302,6 +302,10 @@ public class FusionEngine implements LocationListener {
                    0.0, 360.0));
        }

        if (mNetworkLocation != null) {
            fused.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, mNetworkLocation);
        }

        mFusedLocation = fused;

        mCallback.reportLocation(mFusedLocation);
+75 −36
Original line number Diff line number Diff line
@@ -900,10 +900,26 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        return receiver;
    }

    private boolean isProviderAllowedByCoarsePermission(String provider) {
        if (LocationManager.FUSED_PROVIDER.equals(provider)) {
            return true;
        }
        if (LocationManager.PASSIVE_PROVIDER.equals(provider)) {
            return true;
        }
        if (LocationManager.NETWORK_PROVIDER.equals(provider)) {
            return true;
        }
        return false;
    }

    private String checkPermissionAndRequest(LocationRequest request) {
        String perm = checkPermission();

        if (ACCESS_COARSE_LOCATION.equals(perm)) {
            if (!isProviderAllowedByCoarsePermission(request.getProvider())) {
                throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
            }
            switch (request.getQuality()) {
                case LocationRequest.ACCURACY_FINE:
                    request.setQuality(LocationRequest.ACCURACY_BLOCK);
@@ -990,7 +1006,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        // use the fused provider
        if (request == null) request = DEFAULT_LOCATION_REQUEST;
        String name = request.getProvider();
        if (name == null) name = LocationManager.FUSED_PROVIDER;
        if (name == null) {
            throw new IllegalArgumentException("provider name must not be null");
        }
        LocationProviderInterface provider = mProvidersByName.get(name);
        if (provider == null) {
            throw new IllegalArgumentException("provider doesn't exisit: " + provider);
@@ -1094,13 +1112,20 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
            if (!isAllowedBySettingsLocked(name)) return null;

            Location location = mLastLocation.get(name);
            if (location == null) {
                return null;
            }
            if (ACCESS_FINE_LOCATION.equals(perm)) {
                return location;
            } else {
                return mLocationFudger.getOrCreate(location);
                Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
                if (noGPSLocation != null) {
                    return mLocationFudger.getOrCreate(noGPSLocation);
                }
            }
        }
        return null;
    }

    @Override
    public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
@@ -1329,17 +1354,29 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
        LocationProviderInterface p = mProvidersByName.get(provider);
        if (p == null) return;

        // Add the coarse location as an extra
        Location coarse = mLocationFudger.getOrCreate(location);

        // Update last known locations
        Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
        Location lastNoGPSLocation = null;
        Location lastLocation = mLastLocation.get(provider);
        if (lastLocation == null) {
            lastLocation = new Location(provider);
            mLastLocation.put(provider, lastLocation);
        } else {
            lastNoGPSLocation = lastLocation.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
            if (noGPSLocation == null && lastNoGPSLocation != null) {
                // New location has no no-GPS location: adopt last no-GPS location. This is set
                // directly into location because we do not want to notify COARSE clients.
                location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
            }
        }
        lastLocation.set(location);

        // Fetch coarse location
        Location coarseLocation = null;
        if (noGPSLocation != null && !noGPSLocation.equals(lastNoGPSLocation)) {
            coarseLocation = mLocationFudger.getOrCreate(noGPSLocation);
        }

        // Fetch latest status update time
        long newStatusUpdateTime = p.getStatusUpdateTime();

@@ -1361,25 +1398,27 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
                continue;
            }

            Location notifyLocation = null;
            if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
                location = lastLocation;  // use fine location
                notifyLocation = lastLocation;  // use fine location
            } else {
                location = coarse;  // use coarse location
                notifyLocation = coarseLocation;  // use coarse location if available
            }

            if (notifyLocation != null) {
                Location lastLoc = r.mLastFixBroadcast;
            if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
                if ((lastLoc == null) || shouldBroadcastSafe(notifyLocation, lastLoc, r)) {
                    if (lastLoc == null) {
                    lastLoc = new Location(location);
                        lastLoc = new Location(notifyLocation);
                        r.mLastFixBroadcast = lastLoc;
                    } else {
                    lastLoc.set(location);
                        lastLoc.set(notifyLocation);
                    }
                if (!receiver.callLocationChangedLocked(location)) {
                    if (!receiver.callLocationChangedLocked(notifyLocation)) {
                        Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
                        receiverDead = true;
                    }
                }
            }

            long prevStatusUpdateTime = r.mLastStatusBroadcast;
            if ((newStatusUpdateTime > prevStatusUpdateTime) &&
+4 −16
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import java.security.SecureRandom;
import android.content.Context;
import android.database.ContentObserver;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
@@ -40,8 +41,6 @@ public class LocationFudger {
    private static final boolean D = false;
    private static final String TAG = "LocationFudge";

    private static final String EXTRA_COARSE_LOCATION = "coarseLocation";

    /**
     * Default coarse accuracy in meters.
     */
@@ -168,18 +167,10 @@ public class LocationFudger {
     */
    public Location getOrCreate(Location location) {
        synchronized (mLock) {
            Bundle extras = location.getExtras();
            if (extras == null) {
                return addCoarseLocationExtraLocked(location);
            }
            Parcelable parcel = extras.getParcelable(EXTRA_COARSE_LOCATION);
            if (parcel == null) {
                return addCoarseLocationExtraLocked(location);
            }
            if (!(parcel instanceof Location)) {
            Location coarse = location.getExtraLocation(Location.EXTRA_COARSE_LOCATION);
            if (coarse == null) {
                return addCoarseLocationExtraLocked(location);
            }
            Location coarse = (Location) parcel;
            if (coarse.getAccuracy() < mAccuracyInMeters) {
                return addCoarseLocationExtraLocked(location);
            }
@@ -188,11 +179,8 @@ public class LocationFudger {
    }

    private Location addCoarseLocationExtraLocked(Location location) {
        Bundle extras = location.getExtras();
        if (extras == null) extras = new Bundle();
        Location coarse = createCoarseLocked(location);
        extras.putParcelable(EXTRA_COARSE_LOCATION, coarse);
        location.setExtras(extras);
        location.setExtraLocation(Location.EXTRA_COARSE_LOCATION, coarse);
        return coarse;
    }

Loading