Merge "LocationManager permissions cleanup" into jb-mr1-dev

This commit is contained in:
Victoria Lease
2012-10-18 11:02:51 -07:00
committed by Android (Google) Code Review
2 changed files with 154 additions and 101 deletions

View File

@@ -221,6 +221,18 @@ public final class LocationRequest implements Parcelable {
/** @hide */ /** @hide */
public LocationRequest() { } public LocationRequest() { }
/** @hide */
public LocationRequest(LocationRequest src) {
mQuality = src.mQuality;
mInterval = src.mInterval;
mFastestInterval = src.mFastestInterval;
mExplicitFastestInterval = src.mExplicitFastestInterval;
mExpireAt = src.mExpireAt;
mNumUpdates = src.mNumUpdates;
mSmallestDisplacement = src.mSmallestDisplacement;
mProvider = src.mProvider;
}
/** /**
* Set the quality of the request. * Set the quality of the request.
* *

View File

@@ -90,10 +90,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
private static final String WAKELOCK_KEY = TAG; private static final String WAKELOCK_KEY = TAG;
private static final String THREAD_NAME = TAG; private static final String THREAD_NAME = TAG;
private static final String ACCESS_FINE_LOCATION = // Location resolution level: no location data whatsoever
android.Manifest.permission.ACCESS_FINE_LOCATION; private static final int RESOLUTION_LEVEL_NONE = 0;
private static final String ACCESS_COARSE_LOCATION = // Location resolution level: coarse location data only
android.Manifest.permission.ACCESS_COARSE_LOCATION; private static final int RESOLUTION_LEVEL_COARSE = 1;
// Location resolution level: fine location data
private static final int RESOLUTION_LEVEL_FINE = 2;
private static final String ACCESS_MOCK_LOCATION = private static final String ACCESS_MOCK_LOCATION =
android.Manifest.permission.ACCESS_MOCK_LOCATION; android.Manifest.permission.ACCESS_MOCK_LOCATION;
private static final String ACCESS_LOCATION_EXTRA_COMMANDS = private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
@@ -347,7 +350,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
final int mUid; // uid of receiver final int mUid; // uid of receiver
final int mPid; // pid of receiver final int mPid; // pid of receiver
final String mPackageName; // package name of receiver final String mPackageName; // package name of receiver
final String mPermission; // best permission that receiver has final int mAllowedResolutionLevel; // resolution level allowed to receiver
final ILocationListener mListener; final ILocationListener mListener;
final PendingIntent mPendingIntent; final PendingIntent mPendingIntent;
@@ -366,7 +369,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
} else { } else {
mKey = intent; mKey = intent;
} }
mPermission = checkPermission(); mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
mUid = uid; mUid = uid;
mPid = pid; mPid = pid;
mPackageName = packageName; mPackageName = packageName;
@@ -440,7 +443,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
// synchronize to ensure incrementPendingBroadcastsLocked() // synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts() // is called before decrementPendingBroadcasts()
mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler, mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
mPermission); getResolutionPermission(mAllowedResolutionLevel));
// call this after broadcasting so we do not increment // call this after broadcasting so we do not increment
// if we throw an exeption. // if we throw an exeption.
incrementPendingBroadcastsLocked(); incrementPendingBroadcastsLocked();
@@ -474,7 +477,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
// synchronize to ensure incrementPendingBroadcastsLocked() // synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts() // is called before decrementPendingBroadcasts()
mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler, mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
mPermission); getResolutionPermission(mAllowedResolutionLevel));
// call this after broadcasting so we do not increment // call this after broadcasting so we do not increment
// if we throw an exeption. // if we throw an exeption.
incrementPendingBroadcastsLocked(); incrementPendingBroadcastsLocked();
@@ -512,7 +515,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
// synchronize to ensure incrementPendingBroadcastsLocked() // synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts() // is called before decrementPendingBroadcasts()
mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler, mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
mPermission); getResolutionPermission(mAllowedResolutionLevel));
// call this after broadcasting so we do not increment // call this after broadcasting so we do not increment
// if we throw an exeption. // if we throw an exeption.
incrementPendingBroadcastsLocked(); incrementPendingBroadcastsLocked();
@@ -609,51 +612,76 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
} }
/** /**
* Returns the best permission available to the caller. * Returns the permission string associated with the specified resolution level.
*
* @param resolutionLevel the resolution level
* @return the permission string
*/ */
private String getBestCallingPermission() { private String getResolutionPermission(int resolutionLevel) {
if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) == switch (resolutionLevel) {
PackageManager.PERMISSION_GRANTED) { case RESOLUTION_LEVEL_FINE:
return ACCESS_FINE_LOCATION; return android.Manifest.permission.ACCESS_FINE_LOCATION;
} else if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) == case RESOLUTION_LEVEL_COARSE:
PackageManager.PERMISSION_GRANTED) { return android.Manifest.permission.ACCESS_COARSE_LOCATION;
return ACCESS_COARSE_LOCATION; default:
return null;
} }
return null;
} }
/** /**
* Throw SecurityException if caller has neither COARSE or FINE. * Returns the resolution level allowed to the given PID/UID pair.
* Otherwise, return the best permission. *
* @param pid the PID
* @param uid the UID
* @return resolution level allowed to the pid/uid pair
*/ */
private String checkPermission() { private int getAllowedResolutionLevel(int pid, int uid) {
String perm = getBestCallingPermission(); if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
if (perm == null) { pid, uid) == PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" + return RESOLUTION_LEVEL_FINE;
" ACCESS_FINE_LOCATION permission"); } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
pid, uid) == PackageManager.PERMISSION_GRANTED) {
return RESOLUTION_LEVEL_COARSE;
} else {
return RESOLUTION_LEVEL_NONE;
} }
return perm;
} }
/** /**
* Throw SecurityException if caller lacks permission to use Geofences. * Returns the resolution level allowed to the caller
*
* @return resolution level allowed to caller
*/ */
private void checkGeofencePermission() { private int getCallerAllowedResolutionLevel() {
if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) != return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
PackageManager.PERMISSION_GRANTED) { }
/**
* Throw SecurityException if specified resolution level is insufficient to use geofences.
*
* @param allowedResolutionLevel resolution level allowed to caller
*/
private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission"); throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
} }
} }
private String getMinimumPermissionForProvider(String provider) { /**
* Return the minimum resolution level required to use the specified location provider.
*
* @param provider the name of the location provider
* @return minimum resolution level required for provider
*/
private int getMinimumResolutionLevelForProviderUse(String provider) {
if (LocationManager.GPS_PROVIDER.equals(provider) || if (LocationManager.GPS_PROVIDER.equals(provider) ||
LocationManager.PASSIVE_PROVIDER.equals(provider)) { LocationManager.PASSIVE_PROVIDER.equals(provider)) {
// gps and passive providers require FINE permission // gps and passive providers require FINE permission
return ACCESS_FINE_LOCATION; return RESOLUTION_LEVEL_FINE;
} else if (LocationManager.NETWORK_PROVIDER.equals(provider) || } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
LocationManager.FUSED_PROVIDER.equals(provider)) { LocationManager.FUSED_PROVIDER.equals(provider)) {
// network and fused providers are ok with COARSE or FINE // network and fused providers are ok with COARSE or FINE
return ACCESS_COARSE_LOCATION; return RESOLUTION_LEVEL_COARSE;
} else { } else {
// mock providers // mock providers
LocationProviderInterface lp = mMockProviders.get(provider); LocationProviderInterface lp = mMockProviders.get(provider);
@@ -662,41 +690,38 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
if (properties != null) { if (properties != null) {
if (properties.mRequiresSatellite) { if (properties.mRequiresSatellite) {
// provider requiring satellites require FINE permission // provider requiring satellites require FINE permission
return ACCESS_FINE_LOCATION; return RESOLUTION_LEVEL_FINE;
} else if (properties.mRequiresNetwork || properties.mRequiresCell) { } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
// provider requiring network and or cell require COARSE or FINE // provider requiring network and or cell require COARSE or FINE
return ACCESS_COARSE_LOCATION; return RESOLUTION_LEVEL_COARSE;
} }
} }
} }
} }
return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
return null;
} }
private boolean isPermissionSufficient(String perm, String minPerm) { /**
if (ACCESS_FINE_LOCATION.equals(minPerm)) { * Throw SecurityException if specified resolution level is insufficient to use the named
return ACCESS_FINE_LOCATION.equals(perm); * location provider.
} else if (ACCESS_COARSE_LOCATION.equals(minPerm)) { *
return ACCESS_FINE_LOCATION.equals(perm) || * @param allowedResolutionLevel resolution level allowed to caller
ACCESS_COARSE_LOCATION.equals(perm); * @param providerName the name of the location provider
} else { */
return false; private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
} String providerName) {
} int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
if (allowedResolutionLevel < requiredResolutionLevel) {
private void checkPermissionForProvider(String perm, String provider) { switch (requiredResolutionLevel) {
String minPerm = getMinimumPermissionForProvider(provider); case RESOLUTION_LEVEL_FINE:
if (!isPermissionSufficient(perm, minPerm)) { throw new SecurityException("\"" + providerName + "\" location provider " +
if (ACCESS_FINE_LOCATION.equals(minPerm)) { "requires ACCESS_FINE_LOCATION permission.");
throw new SecurityException("Location provider \"" + provider + case RESOLUTION_LEVEL_COARSE:
"\" requires ACCESS_FINE_LOCATION permission."); throw new SecurityException("\"" + providerName + "\" location provider " +
} else if (ACCESS_COARSE_LOCATION.equals(minPerm)) { "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
throw new SecurityException("Location provider \"" + provider + default:
"\" requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission."); throw new SecurityException("Insufficient permission for \"" + providerName +
} else { "\" location provider.");
throw new SecurityException("Insufficient permission for location provider \"" +
provider + "\".");
} }
} }
} }
@@ -731,8 +756,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
*/ */
@Override @Override
public List<String> getProviders(Criteria criteria, boolean enabledOnly) { public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
ArrayList<String> out; ArrayList<String> out;
String perm = getBestCallingPermission();
int callingUserId = UserHandle.getCallingUserId(); int callingUserId = UserHandle.getCallingUserId();
long identity = Binder.clearCallingIdentity(); long identity = Binder.clearCallingIdentity();
try { try {
@@ -743,7 +768,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
if (LocationManager.FUSED_PROVIDER.equals(name)) { if (LocationManager.FUSED_PROVIDER.equals(name)) {
continue; continue;
} }
if (isPermissionSufficient(perm, getMinimumPermissionForProvider(name))) { if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) { if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) {
continue; continue;
} }
@@ -803,8 +828,6 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
@Override @Override
public boolean providerMeetsCriteria(String provider, Criteria criteria) { public boolean providerMeetsCriteria(String provider, Criteria criteria) {
checkPermission();
LocationProviderInterface p = mProvidersByName.get(provider); LocationProviderInterface p = mProvidersByName.get(provider);
if (p == null) { if (p == null) {
throw new IllegalArgumentException("provider=" + provider); throw new IllegalArgumentException("provider=" + provider);
@@ -1010,33 +1033,41 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
return receiver; return receiver;
} }
private String checkPermissionAndRequest(LocationRequest request) { /**
String perm = getBestCallingPermission(); * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
String provider = request.getProvider(); * and consistency requirements.
checkPermissionForProvider(perm, provider); *
* @param request the LocationRequest from which to create a sanitized version
if (ACCESS_COARSE_LOCATION.equals(perm)) { * @param shouldBeCoarse whether the sanitized version should be held to coarse resolution
switch (request.getQuality()) { * constraints
* @param fastestCoarseIntervalMS minimum interval allowed for coarse resolution
* @return a version of request that meets the given resolution and consistency requirements
* @hide
*/
private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
LocationRequest sanitizedRequest = new LocationRequest(request);
if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
switch (sanitizedRequest.getQuality()) {
case LocationRequest.ACCURACY_FINE: case LocationRequest.ACCURACY_FINE:
request.setQuality(LocationRequest.ACCURACY_BLOCK); sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
break; break;
case LocationRequest.POWER_HIGH: case LocationRequest.POWER_HIGH:
request.setQuality(LocationRequest.POWER_LOW); sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
break; break;
} }
// throttle // throttle
if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) { if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
request.setInterval(LocationFudger.FASTEST_INTERVAL_MS); sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
} }
if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) { if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS); sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
} }
} }
// make getFastestInterval() the minimum of interval and fastest interval // make getFastestInterval() the minimum of interval and fastest interval
if (request.getFastestInterval() > request.getInterval()) { if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
request.setFastestInterval(request.getInterval()); request.setFastestInterval(request.getInterval());
} }
return perm; return sanitizedRequest;
} }
private void checkPackageName(String packageName) { private void checkPackageName(String packageName) {
@@ -1079,7 +1110,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
PendingIntent intent, String packageName) { PendingIntent intent, String packageName) {
if (request == null) request = DEFAULT_LOCATION_REQUEST; if (request == null) request = DEFAULT_LOCATION_REQUEST;
checkPackageName(packageName); checkPackageName(packageName);
checkPermissionAndRequest(request); int allowedResolutionLevel = getCallerAllowedResolutionLevel();
checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
request.getProvider());
LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
final int pid = Binder.getCallingPid(); final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid(); final int uid = Binder.getCallingUid();
@@ -1089,7 +1123,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
long identity = Binder.clearCallingIdentity(); long identity = Binder.clearCallingIdentity();
try { try {
synchronized (mLock) { synchronized (mLock) {
requestLocationUpdatesLocked(request, recevier, pid, uid, packageName); requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
} }
} finally { } finally {
Binder.restoreCallingIdentity(identity); Binder.restoreCallingIdentity(identity);
@@ -1132,7 +1166,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
public void removeUpdates(ILocationListener listener, PendingIntent intent, public void removeUpdates(ILocationListener listener, PendingIntent intent,
String packageName) { String packageName) {
checkPackageName(packageName); checkPackageName(packageName);
checkPermission();
final int pid = Binder.getCallingPid(); final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid(); final int uid = Binder.getCallingUid();
Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName); Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
@@ -1188,8 +1222,11 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
public Location getLastLocation(LocationRequest request, String packageName) { public Location getLastLocation(LocationRequest request, String packageName) {
if (D) Log.d(TAG, "getLastLocation: " + request); if (D) Log.d(TAG, "getLastLocation: " + request);
if (request == null) request = DEFAULT_LOCATION_REQUEST; if (request == null) request = DEFAULT_LOCATION_REQUEST;
String perm = checkPermissionAndRequest(request); int allowedResolutionLevel = getCallerAllowedResolutionLevel();
checkPackageName(packageName); checkPackageName(packageName);
checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
request.getProvider());
// no need to sanitize this request, as only the provider name is used
long identity = Binder.clearCallingIdentity(); long identity = Binder.clearCallingIdentity();
try { try {
@@ -1213,13 +1250,13 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
if (location == null) { if (location == null) {
return null; return null;
} }
if (ACCESS_FINE_LOCATION.equals(perm)) { if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
return location;
} else {
Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION); Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
if (noGPSLocation != null) { if (noGPSLocation != null) {
return mLocationFudger.getOrCreate(noGPSLocation); return mLocationFudger.getOrCreate(noGPSLocation);
} }
} else {
return location;
} }
} }
return null; return null;
@@ -1232,18 +1269,21 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent, public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
String packageName) { String packageName) {
if (request == null) request = DEFAULT_LOCATION_REQUEST; if (request == null) request = DEFAULT_LOCATION_REQUEST;
checkGeofencePermission(); int allowedResolutionLevel = getCallerAllowedResolutionLevel();
checkPermissionAndRequest(request); checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
checkPendingIntent(intent); checkPendingIntent(intent);
checkPackageName(packageName); checkPackageName(packageName);
checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
request.getProvider());
LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent); if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
// geo-fence manager uses the public location API, need to clear identity // geo-fence manager uses the public location API, need to clear identity
int uid = Binder.getCallingUid(); int uid = Binder.getCallingUid();
long identity = Binder.clearCallingIdentity(); long identity = Binder.clearCallingIdentity();
try { try {
mGeofenceManager.addFence(request, geofence, intent, uid, packageName); mGeofenceManager.addFence(sanitizedRequest, geofence, intent, uid, packageName);
} finally { } finally {
Binder.restoreCallingIdentity(identity); Binder.restoreCallingIdentity(identity);
} }
@@ -1251,7 +1291,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
@Override @Override
public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) { public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
checkGeofencePermission(); checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
checkPendingIntent(intent); checkPendingIntent(intent);
checkPackageName(packageName); checkPackageName(packageName);
@@ -1272,10 +1312,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
if (mGpsStatusProvider == null) { if (mGpsStatusProvider == null) {
return false; return false;
} }
if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) != checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
PackageManager.PERMISSION_GRANTED) { LocationManager.GPS_PROVIDER);
throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
}
try { try {
mGpsStatusProvider.addGpsStatusListener(listener); mGpsStatusProvider.addGpsStatusListener(listener);
@@ -1303,8 +1341,9 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
// throw NullPointerException to remain compatible with previous implementation // throw NullPointerException to remain compatible with previous implementation
throw new NullPointerException(); throw new NullPointerException();
} }
checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
provider);
checkPermission();
// and check for ACCESS_LOCATION_EXTRA_COMMANDS // and check for ACCESS_LOCATION_EXTRA_COMMANDS
if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS) if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
!= PackageManager.PERMISSION_GRANTED)) { != PackageManager.PERMISSION_GRANTED)) {
@@ -1344,7 +1383,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
return null; return null;
} }
checkPermissionForProvider(getBestCallingPermission(), provider); checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
provider);
LocationProviderInterface p; LocationProviderInterface p;
synchronized (mLock) { synchronized (mLock) {
@@ -1357,7 +1397,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
@Override @Override
public boolean isProviderEnabled(String provider) { public boolean isProviderEnabled(String provider) {
checkPermissionForProvider(getBestCallingPermission(), provider); checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
provider);
if (LocationManager.FUSED_PROVIDER.equals(provider)) return false; if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
long identity = Binder.clearCallingIdentity(); long identity = Binder.clearCallingIdentity();
@@ -1522,10 +1563,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
} }
Location notifyLocation = null; Location notifyLocation = null;
if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) { if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
notifyLocation = lastLocation; // use fine location notifyLocation = coarseLocation; // use coarse location
} else { } else {
notifyLocation = coarseLocation; // use coarse location if available notifyLocation = lastLocation; // use fine location
} }
if (notifyLocation != null) { if (notifyLocation != null) {
Location lastLoc = r.mLastFixBroadcast; Location lastLoc = r.mLastFixBroadcast;