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

Commit e2052a33 authored by Victoria Lease's avatar Victoria Lease Committed by Android (Google) Code Review
Browse files

Merge "Secure setting for LocationFudger's accuracy" into jb-mr1-dev

parents 2a4057d2 df9ec617
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -210,7 +210,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run

        mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
        mBlacklist.init();
        mLocationFudger = new LocationFudger();
        mLocationFudger = new LocationFudger(mContext, mLocationHandler);

        synchronized (mLock) {
            loadProvidersLocked();
+133 −46
Original line number Diff line number Diff line
@@ -19,10 +19,14 @@ package com.android.server.location;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.security.SecureRandom;
import android.content.Context;
import android.database.ContentObserver;
import android.location.Location;
import android.os.Bundle;
import android.os.Handler;
import android.os.Parcelable;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.Log;


@@ -39,22 +43,19 @@ public class LocationFudger {
    private static final String EXTRA_COARSE_LOCATION = "coarseLocation";

    /**
     * This is the main control: Best location accuracy allowed for coarse applications.
     * Default coarse accuracy in meters.
     */
    private static final float ACCURACY_METERS = 200.0f;
    private static final float DEFAULT_ACCURACY_IN_METERS = 2000.0f;

    /**
     * The distance between grids for snap-to-grid. See {@link #createCoarse}.
     * Minimum coarse accuracy in meters.
     */
    private static final double GRID_SIZE_METERS = ACCURACY_METERS;
    private static final float MINIMUM_ACCURACY_IN_METERS = 200.0f;

    /**
     * Standard deviation of the (normally distributed) random offset applied
     * to coarse locations. It does not need to be as large as
     * {@link #COARSE_ACCURACY_METERS} because snap-to-grid is the primary obfuscation
     * method. See further details in the implementation.
     * Secure settings key for coarse accuracy.
     */
    private static final double STANDARD_DEVIATION_METERS = GRID_SIZE_METERS / 4.0;
    private static final String COARSE_ACCURACY_CONFIG_NAME = "locationCoarseAccuracy";

    /**
     * This is the fastest interval that applications can receive coarse
@@ -106,43 +107,90 @@ public class LocationFudger {
    private final Object mLock = new Object();
    private final SecureRandom mRandom = new SecureRandom();

    /**
     * Used to monitor coarse accuracy secure setting for changes.
     */
    private final ContentObserver mSettingsObserver;

    /**
     * Used to resolve coarse accuracy setting.
     */
    private final Context mContext;

    // all fields below protected by mLock
    private double mOffsetLatitudeMeters;
    private double mOffsetLongitudeMeters;
    private long mNextInterval;

    public LocationFudger() {
        mOffsetLatitudeMeters = nextOffset();
        mOffsetLongitudeMeters = nextOffset();
    /**
     * Best location accuracy allowed for coarse applications.
     * This value should only be set by {@link #setAccuracyInMetersLocked(float)}.
     */
    private float mAccuracyInMeters;

    /**
     * The distance between grids for snap-to-grid. See {@link #createCoarse}.
     * This value should only be set by {@link #setAccuracyInMetersLocked(float)}.
     */
    private double mGridSizeInMeters;

    /**
     * Standard deviation of the (normally distributed) random offset applied
     * to coarse locations. It does not need to be as large as
     * {@link #COARSE_ACCURACY_METERS} because snap-to-grid is the primary obfuscation
     * method. See further details in the implementation.
     * This value should only be set by {@link #setAccuracyInMetersLocked(float)}.
     */
    private double mStandardDeviationInMeters;

    public LocationFudger(Context context, Handler handler) {
        mContext = context;
        mSettingsObserver = new ContentObserver(handler) {
            @Override
            public void onChange(boolean selfChange) {
                setAccuracyInMeters(loadCoarseAccuracy());
            }
        };
        mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
                COARSE_ACCURACY_CONFIG_NAME), false, mSettingsObserver);

        float accuracy = loadCoarseAccuracy();
        synchronized (mLock) {
            setAccuracyInMetersLocked(accuracy);
            mOffsetLatitudeMeters = nextOffsetLocked();
            mOffsetLongitudeMeters = nextOffsetLocked();
            mNextInterval = SystemClock.elapsedRealtime() + CHANGE_INTERVAL_MS;
        }
    }

    /**
     * Get the cached coarse location, or generate a new one and cache it.
     */
    public Location getOrCreate(Location location) {
        synchronized (mLock) {
            Bundle extras = location.getExtras();
            if (extras == null) {
            return addCoarseLocationExtra(location);
                return addCoarseLocationExtraLocked(location);
            }
            Parcelable parcel = extras.getParcelable(EXTRA_COARSE_LOCATION);
            if (parcel == null) {
            return addCoarseLocationExtra(location);
                return addCoarseLocationExtraLocked(location);
            }
            if (!(parcel instanceof Location)) {
            return addCoarseLocationExtra(location);
                return addCoarseLocationExtraLocked(location);
            }
            Location coarse = (Location) parcel;
        if (coarse.getAccuracy() < ACCURACY_METERS) {
            return addCoarseLocationExtra(location);
            if (coarse.getAccuracy() < mAccuracyInMeters) {
                return addCoarseLocationExtraLocked(location);
            }
            return coarse;
        }
    }

    private Location addCoarseLocationExtra(Location location) {
    private Location addCoarseLocationExtraLocked(Location location) {
        Bundle extras = location.getExtras();
        if (extras == null) extras = new Bundle();
        Location coarse = createCoarse(location);
        Location coarse = createCoarseLocked(location);
        extras.putParcelable(EXTRA_COARSE_LOCATION, coarse);
        location.setExtras(extras);
        return coarse;
@@ -163,7 +211,7 @@ public class LocationFudger {
     * producing stable results, and mitigating against taking many samples
     * to average out a random offset.
     */
    private Location createCoarse(Location fine) {
    private Location createCoarseLocked(Location fine) {
        Location coarse = new Location(fine);

        // clean all the optional information off the location, because
@@ -188,14 +236,12 @@ public class LocationFudger {
        //
        // We apply the offset even if the location already claims to be
        // inaccurate, because it may be more accurate than claimed.
        synchronized (mLock) {
        updateRandomOffsetLocked();
        // perform lon first whilst lat is still within bounds
        lon += metersToDegreesLongitude(mOffsetLongitudeMeters, lat);
        lat += metersToDegreesLatitude(mOffsetLatitudeMeters);
        if (D) Log.d(TAG, String.format("applied offset of %.0f, %.0f (meters)",
                mOffsetLongitudeMeters, mOffsetLatitudeMeters));
        }

        // wrap
        lat = wrapLatitude(lat);
@@ -211,9 +257,9 @@ public class LocationFudger {
        // Note we quantize the latitude first, since the longitude
        // quantization depends on the latitude value and so leaks information
        // about the latitude
        double latGranularity = metersToDegreesLatitude(GRID_SIZE_METERS);
        double latGranularity = metersToDegreesLatitude(mGridSizeInMeters);
        lat = Math.round(lat / latGranularity) * latGranularity;
        double lonGranularity = metersToDegreesLongitude(GRID_SIZE_METERS, lat);
        double lonGranularity = metersToDegreesLongitude(mGridSizeInMeters, lat);
        lon = Math.round(lon / lonGranularity) * lonGranularity;

        // wrap again
@@ -223,7 +269,7 @@ public class LocationFudger {
        // apply
        coarse.setLatitude(lat);
        coarse.setLongitude(lon);
        coarse.setAccuracy(Math.max(ACCURACY_METERS, coarse.getAccuracy()));
        coarse.setAccuracy(Math.max(mAccuracyInMeters, coarse.getAccuracy()));

        if (D) Log.d(TAG, "fudged " + fine + " to " + coarse);
        return coarse;
@@ -259,16 +305,16 @@ public class LocationFudger {
        mNextInterval = now + CHANGE_INTERVAL_MS;

        mOffsetLatitudeMeters *= PREVIOUS_WEIGHT;
        mOffsetLatitudeMeters += NEW_WEIGHT * nextOffset();
        mOffsetLatitudeMeters += NEW_WEIGHT * nextOffsetLocked();
        mOffsetLongitudeMeters *= PREVIOUS_WEIGHT;
        mOffsetLongitudeMeters += NEW_WEIGHT * nextOffset();
        mOffsetLongitudeMeters += NEW_WEIGHT * nextOffsetLocked();

        if (D) Log.d(TAG, String.format("new offset: %.0f, %.0f (meters)",
                mOffsetLongitudeMeters, mOffsetLatitudeMeters));
    }

    private double nextOffset() {
        return mRandom.nextGaussian() * STANDARD_DEVIATION_METERS;
    private double nextOffsetLocked() {
        return mRandom.nextGaussian() * mStandardDeviationInMeters;
    }

    private static double wrapLatitude(double lat) {
@@ -307,4 +353,45 @@ public class LocationFudger {
        pw.println(String.format("offset: %.0f, %.0f (meters)", mOffsetLongitudeMeters,
                mOffsetLatitudeMeters));
    }

    /**
     * This is the main control: call this to set the best location accuracy
     * allowed for coarse applications and all derived values.
     */
    private void setAccuracyInMetersLocked(float accuracyInMeters) {
        mAccuracyInMeters = Math.max(accuracyInMeters, MINIMUM_ACCURACY_IN_METERS);
        if (D) {
            Log.d(TAG, "setAccuracyInMetersLocked: new accuracy = " + mAccuracyInMeters);
        }
        mGridSizeInMeters = mAccuracyInMeters;
        mStandardDeviationInMeters = mGridSizeInMeters / 4.0;
    }

    /**
     * Same as setAccuracyInMetersLocked without the pre-lock requirement.
     */
    private void setAccuracyInMeters(float accuracyInMeters) {
        synchronized (mLock) {
            setAccuracyInMetersLocked(accuracyInMeters);
        }
    }

    /**
     * Loads the coarse accuracy value from secure settings.
     */
    private float loadCoarseAccuracy() {
        String newSetting = Settings.Secure.getString(mContext.getContentResolver(),
                COARSE_ACCURACY_CONFIG_NAME);
        if (D) {
            Log.d(TAG, "loadCoarseAccuracy: newSetting = \"" + newSetting + "\"");
        }
        if (newSetting == null) {
            return DEFAULT_ACCURACY_IN_METERS;
        }
        try {
            return Float.parseFloat(newSetting);
        } catch (NumberFormatException e) {
            return DEFAULT_ACCURACY_IN_METERS;
        }
    }
}