Skip to content

Commit e2052a3

Browse files
Victoria LeaseAndroid (Google) Code Review
authored andcommitted
Merge "Secure setting for LocationFudger's accuracy" into jb-mr1-dev
2 parents 2a4057d + df9ec61 commit e2052a3

File tree

2 files changed

+134
-47
lines changed

2 files changed

+134
-47
lines changed

services/java/com/android/server/LocationManagerService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ private void init() {
210210

211211
mBlacklist = new LocationBlacklist(mContext, mLocationHandler);
212212
mBlacklist.init();
213-
mLocationFudger = new LocationFudger();
213+
mLocationFudger = new LocationFudger(mContext, mLocationHandler);
214214

215215
synchronized (mLock) {
216216
loadProvidersLocked();

services/java/com/android/server/location/LocationFudger.java

Lines changed: 133 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@
1919
import java.io.FileDescriptor;
2020
import java.io.PrintWriter;
2121
import java.security.SecureRandom;
22+
import android.content.Context;
23+
import android.database.ContentObserver;
2224
import android.location.Location;
2325
import android.os.Bundle;
26+
import android.os.Handler;
2427
import android.os.Parcelable;
2528
import android.os.SystemClock;
29+
import android.provider.Settings;
2630
import android.util.Log;
2731

2832

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

4145
/**
42-
* This is the main control: Best location accuracy allowed for coarse applications.
46+
* Default coarse accuracy in meters.
4347
*/
44-
private static final float ACCURACY_METERS = 200.0f;
48+
private static final float DEFAULT_ACCURACY_IN_METERS = 2000.0f;
4549

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

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

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

110+
/**
111+
* Used to monitor coarse accuracy secure setting for changes.
112+
*/
113+
private final ContentObserver mSettingsObserver;
114+
115+
/**
116+
* Used to resolve coarse accuracy setting.
117+
*/
118+
private final Context mContext;
119+
109120
// all fields below protected by mLock
110121
private double mOffsetLatitudeMeters;
111122
private double mOffsetLongitudeMeters;
112123
private long mNextInterval;
113124

114-
public LocationFudger() {
115-
mOffsetLatitudeMeters = nextOffset();
116-
mOffsetLongitudeMeters = nextOffset();
117-
mNextInterval = SystemClock.elapsedRealtime() + CHANGE_INTERVAL_MS;
125+
/**
126+
* Best location accuracy allowed for coarse applications.
127+
* This value should only be set by {@link #setAccuracyInMetersLocked(float)}.
128+
*/
129+
private float mAccuracyInMeters;
130+
131+
/**
132+
* The distance between grids for snap-to-grid. See {@link #createCoarse}.
133+
* This value should only be set by {@link #setAccuracyInMetersLocked(float)}.
134+
*/
135+
private double mGridSizeInMeters;
136+
137+
/**
138+
* Standard deviation of the (normally distributed) random offset applied
139+
* to coarse locations. It does not need to be as large as
140+
* {@link #COARSE_ACCURACY_METERS} because snap-to-grid is the primary obfuscation
141+
* method. See further details in the implementation.
142+
* This value should only be set by {@link #setAccuracyInMetersLocked(float)}.
143+
*/
144+
private double mStandardDeviationInMeters;
145+
146+
public LocationFudger(Context context, Handler handler) {
147+
mContext = context;
148+
mSettingsObserver = new ContentObserver(handler) {
149+
@Override
150+
public void onChange(boolean selfChange) {
151+
setAccuracyInMeters(loadCoarseAccuracy());
152+
}
153+
};
154+
mContext.getContentResolver().registerContentObserver(Settings.Secure.getUriFor(
155+
COARSE_ACCURACY_CONFIG_NAME), false, mSettingsObserver);
156+
157+
float accuracy = loadCoarseAccuracy();
158+
synchronized (mLock) {
159+
setAccuracyInMetersLocked(accuracy);
160+
mOffsetLatitudeMeters = nextOffsetLocked();
161+
mOffsetLongitudeMeters = nextOffsetLocked();
162+
mNextInterval = SystemClock.elapsedRealtime() + CHANGE_INTERVAL_MS;
163+
}
118164
}
119165

120166
/**
121167
* Get the cached coarse location, or generate a new one and cache it.
122168
*/
123169
public Location getOrCreate(Location location) {
124-
Bundle extras = location.getExtras();
125-
if (extras == null) {
126-
return addCoarseLocationExtra(location);
127-
}
128-
Parcelable parcel = extras.getParcelable(EXTRA_COARSE_LOCATION);
129-
if (parcel == null) {
130-
return addCoarseLocationExtra(location);
131-
}
132-
if (!(parcel instanceof Location)) {
133-
return addCoarseLocationExtra(location);
134-
}
135-
Location coarse = (Location) parcel;
136-
if (coarse.getAccuracy() < ACCURACY_METERS) {
137-
return addCoarseLocationExtra(location);
170+
synchronized (mLock) {
171+
Bundle extras = location.getExtras();
172+
if (extras == null) {
173+
return addCoarseLocationExtraLocked(location);
174+
}
175+
Parcelable parcel = extras.getParcelable(EXTRA_COARSE_LOCATION);
176+
if (parcel == null) {
177+
return addCoarseLocationExtraLocked(location);
178+
}
179+
if (!(parcel instanceof Location)) {
180+
return addCoarseLocationExtraLocked(location);
181+
}
182+
Location coarse = (Location) parcel;
183+
if (coarse.getAccuracy() < mAccuracyInMeters) {
184+
return addCoarseLocationExtraLocked(location);
185+
}
186+
return coarse;
138187
}
139-
return coarse;
140188
}
141189

142-
private Location addCoarseLocationExtra(Location location) {
190+
private Location addCoarseLocationExtraLocked(Location location) {
143191
Bundle extras = location.getExtras();
144192
if (extras == null) extras = new Bundle();
145-
Location coarse = createCoarse(location);
193+
Location coarse = createCoarseLocked(location);
146194
extras.putParcelable(EXTRA_COARSE_LOCATION, coarse);
147195
location.setExtras(extras);
148196
return coarse;
@@ -163,7 +211,7 @@ private Location addCoarseLocationExtra(Location location) {
163211
* producing stable results, and mitigating against taking many samples
164212
* to average out a random offset.
165213
*/
166-
private Location createCoarse(Location fine) {
214+
private Location createCoarseLocked(Location fine) {
167215
Location coarse = new Location(fine);
168216

169217
// clean all the optional information off the location, because
@@ -188,14 +236,12 @@ private Location createCoarse(Location fine) {
188236
//
189237
// We apply the offset even if the location already claims to be
190238
// inaccurate, because it may be more accurate than claimed.
191-
synchronized (mLock) {
192-
updateRandomOffsetLocked();
193-
// perform lon first whilst lat is still within bounds
194-
lon += metersToDegreesLongitude(mOffsetLongitudeMeters, lat);
195-
lat += metersToDegreesLatitude(mOffsetLatitudeMeters);
196-
if (D) Log.d(TAG, String.format("applied offset of %.0f, %.0f (meters)",
197-
mOffsetLongitudeMeters, mOffsetLatitudeMeters));
198-
}
239+
updateRandomOffsetLocked();
240+
// perform lon first whilst lat is still within bounds
241+
lon += metersToDegreesLongitude(mOffsetLongitudeMeters, lat);
242+
lat += metersToDegreesLatitude(mOffsetLatitudeMeters);
243+
if (D) Log.d(TAG, String.format("applied offset of %.0f, %.0f (meters)",
244+
mOffsetLongitudeMeters, mOffsetLatitudeMeters));
199245

200246
// wrap
201247
lat = wrapLatitude(lat);
@@ -211,9 +257,9 @@ private Location createCoarse(Location fine) {
211257
// Note we quantize the latitude first, since the longitude
212258
// quantization depends on the latitude value and so leaks information
213259
// about the latitude
214-
double latGranularity = metersToDegreesLatitude(GRID_SIZE_METERS);
260+
double latGranularity = metersToDegreesLatitude(mGridSizeInMeters);
215261
lat = Math.round(lat / latGranularity) * latGranularity;
216-
double lonGranularity = metersToDegreesLongitude(GRID_SIZE_METERS, lat);
262+
double lonGranularity = metersToDegreesLongitude(mGridSizeInMeters, lat);
217263
lon = Math.round(lon / lonGranularity) * lonGranularity;
218264

219265
// wrap again
@@ -223,7 +269,7 @@ private Location createCoarse(Location fine) {
223269
// apply
224270
coarse.setLatitude(lat);
225271
coarse.setLongitude(lon);
226-
coarse.setAccuracy(Math.max(ACCURACY_METERS, coarse.getAccuracy()));
272+
coarse.setAccuracy(Math.max(mAccuracyInMeters, coarse.getAccuracy()));
227273

228274
if (D) Log.d(TAG, "fudged " + fine + " to " + coarse);
229275
return coarse;
@@ -259,16 +305,16 @@ private void updateRandomOffsetLocked() {
259305
mNextInterval = now + CHANGE_INTERVAL_MS;
260306

261307
mOffsetLatitudeMeters *= PREVIOUS_WEIGHT;
262-
mOffsetLatitudeMeters += NEW_WEIGHT * nextOffset();
308+
mOffsetLatitudeMeters += NEW_WEIGHT * nextOffsetLocked();
263309
mOffsetLongitudeMeters *= PREVIOUS_WEIGHT;
264-
mOffsetLongitudeMeters += NEW_WEIGHT * nextOffset();
310+
mOffsetLongitudeMeters += NEW_WEIGHT * nextOffsetLocked();
265311

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

270-
private double nextOffset() {
271-
return mRandom.nextGaussian() * STANDARD_DEVIATION_METERS;
316+
private double nextOffsetLocked() {
317+
return mRandom.nextGaussian() * mStandardDeviationInMeters;
272318
}
273319

274320
private static double wrapLatitude(double lat) {
@@ -307,4 +353,45 @@ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
307353
pw.println(String.format("offset: %.0f, %.0f (meters)", mOffsetLongitudeMeters,
308354
mOffsetLatitudeMeters));
309355
}
356+
357+
/**
358+
* This is the main control: call this to set the best location accuracy
359+
* allowed for coarse applications and all derived values.
360+
*/
361+
private void setAccuracyInMetersLocked(float accuracyInMeters) {
362+
mAccuracyInMeters = Math.max(accuracyInMeters, MINIMUM_ACCURACY_IN_METERS);
363+
if (D) {
364+
Log.d(TAG, "setAccuracyInMetersLocked: new accuracy = " + mAccuracyInMeters);
365+
}
366+
mGridSizeInMeters = mAccuracyInMeters;
367+
mStandardDeviationInMeters = mGridSizeInMeters / 4.0;
368+
}
369+
370+
/**
371+
* Same as setAccuracyInMetersLocked without the pre-lock requirement.
372+
*/
373+
private void setAccuracyInMeters(float accuracyInMeters) {
374+
synchronized (mLock) {
375+
setAccuracyInMetersLocked(accuracyInMeters);
376+
}
377+
}
378+
379+
/**
380+
* Loads the coarse accuracy value from secure settings.
381+
*/
382+
private float loadCoarseAccuracy() {
383+
String newSetting = Settings.Secure.getString(mContext.getContentResolver(),
384+
COARSE_ACCURACY_CONFIG_NAME);
385+
if (D) {
386+
Log.d(TAG, "loadCoarseAccuracy: newSetting = \"" + newSetting + "\"");
387+
}
388+
if (newSetting == null) {
389+
return DEFAULT_ACCURACY_IN_METERS;
390+
}
391+
try {
392+
return Float.parseFloat(newSetting);
393+
} catch (NumberFormatException e) {
394+
return DEFAULT_ACCURACY_IN_METERS;
395+
}
396+
}
310397
}

0 commit comments

Comments
 (0)