Merge "Refactor location permissions code"
This commit is contained in:
committed by
Android (Google) Code Review
commit
3de6f570d6
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.server;
|
||||
|
||||
import static android.Manifest.permission.ACCESS_COARSE_LOCATION;
|
||||
import static android.Manifest.permission.ACCESS_FINE_LOCATION;
|
||||
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
||||
import static android.location.LocationManager.FUSED_PROVIDER;
|
||||
import static android.location.LocationManager.GPS_PROVIDER;
|
||||
@@ -83,6 +85,7 @@ import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.content.PackageMonitor;
|
||||
import com.android.internal.location.ProviderProperties;
|
||||
import com.android.internal.location.ProviderRequest;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.DumpUtils;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.internal.util.Preconditions;
|
||||
@@ -1400,20 +1403,19 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
private String getResolutionPermission(int resolutionLevel) {
|
||||
switch (resolutionLevel) {
|
||||
case RESOLUTION_LEVEL_FINE:
|
||||
return android.Manifest.permission.ACCESS_FINE_LOCATION;
|
||||
return ACCESS_FINE_LOCATION;
|
||||
case RESOLUTION_LEVEL_COARSE:
|
||||
return android.Manifest.permission.ACCESS_COARSE_LOCATION;
|
||||
return ACCESS_COARSE_LOCATION;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private int getAllowedResolutionLevel(int pid, int uid) {
|
||||
if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
pid, uid) == PERMISSION_GRANTED) {
|
||||
if (mContext.checkPermission(ACCESS_FINE_LOCATION, pid, uid) == PERMISSION_GRANTED) {
|
||||
return RESOLUTION_LEVEL_FINE;
|
||||
} else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
|
||||
pid, uid) == PERMISSION_GRANTED) {
|
||||
} else if (mContext.checkPermission(ACCESS_COARSE_LOCATION, pid, uid)
|
||||
== PERMISSION_GRANTED) {
|
||||
return RESOLUTION_LEVEL_COARSE;
|
||||
} else {
|
||||
return RESOLUTION_LEVEL_NONE;
|
||||
@@ -1424,59 +1426,28 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
|
||||
}
|
||||
|
||||
private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
|
||||
if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
|
||||
throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
|
||||
}
|
||||
private boolean checkCallingOrSelfLocationPermission() {
|
||||
return mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) == PERMISSION_GRANTED
|
||||
|| mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
|
||||
== PERMISSION_GRANTED;
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private int getMinimumResolutionLevelForProviderUseLocked(String provider) {
|
||||
if (GPS_PROVIDER.equals(provider) || PASSIVE_PROVIDER.equals(provider)) {
|
||||
// gps and passive providers require FINE permission
|
||||
return RESOLUTION_LEVEL_FINE;
|
||||
} else if (NETWORK_PROVIDER.equals(provider) || FUSED_PROVIDER.equals(provider)) {
|
||||
// network and fused providers are ok with COARSE or FINE
|
||||
return RESOLUTION_LEVEL_COARSE;
|
||||
} else {
|
||||
for (LocationProviderManager lp : mProviderManagers) {
|
||||
if (!lp.getName().equals(provider)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ProviderProperties properties = lp.getProperties();
|
||||
if (properties != null) {
|
||||
if (properties.mRequiresSatellite) {
|
||||
// provider requiring satellites require FINE permission
|
||||
return RESOLUTION_LEVEL_FINE;
|
||||
} else if (properties.mRequiresNetwork || properties.mRequiresCell) {
|
||||
// provider requiring network and or cell require COARSE or FINE
|
||||
return RESOLUTION_LEVEL_COARSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void enforceCallingOrSelfLocationPermission() {
|
||||
if (checkCallingOrSelfLocationPermission()) {
|
||||
return;
|
||||
}
|
||||
|
||||
return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
|
||||
throw new SecurityException("uid " + Binder.getCallingUid() + " does not have "
|
||||
+ ACCESS_COARSE_LOCATION + " or " + ACCESS_FINE_LOCATION + ".");
|
||||
}
|
||||
|
||||
@GuardedBy("mLock")
|
||||
private void checkResolutionLevelIsSufficientForProviderUseLocked(int allowedResolutionLevel,
|
||||
String providerName) {
|
||||
int requiredResolutionLevel = getMinimumResolutionLevelForProviderUseLocked(providerName);
|
||||
if (allowedResolutionLevel < requiredResolutionLevel) {
|
||||
switch (requiredResolutionLevel) {
|
||||
case RESOLUTION_LEVEL_FINE:
|
||||
throw new SecurityException("\"" + providerName + "\" location provider " +
|
||||
"requires ACCESS_FINE_LOCATION permission.");
|
||||
case RESOLUTION_LEVEL_COARSE:
|
||||
throw new SecurityException("\"" + providerName + "\" location provider " +
|
||||
"requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
|
||||
default:
|
||||
throw new SecurityException("Insufficient permission for \"" + providerName +
|
||||
"\" location provider.");
|
||||
}
|
||||
private void enforceCallingOrSelfPackageName(String packageName) {
|
||||
int uid = Binder.getCallingUid();
|
||||
if (ArrayUtils.contains(mPackageManager.getPackagesForUid(uid), packageName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new SecurityException("invalid package \"" + packageName + "\" for uid " + uid);
|
||||
}
|
||||
|
||||
public static int resolutionLevelToOp(int allowedResolutionLevel) {
|
||||
@@ -1552,7 +1523,10 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
*/
|
||||
@Override
|
||||
public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
|
||||
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
|
||||
if (!checkCallingOrSelfLocationPermission()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
synchronized (mLock) {
|
||||
ArrayList<String> providers = new ArrayList<>(mProviderManagers.size());
|
||||
for (LocationProviderManager manager : mProviderManagers) {
|
||||
@@ -1560,9 +1534,6 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
if (FUSED_PROVIDER.equals(name)) {
|
||||
continue;
|
||||
}
|
||||
if (allowedResolutionLevel < getMinimumResolutionLevelForProviderUseLocked(name)) {
|
||||
continue;
|
||||
}
|
||||
if (enabledOnly && !manager.isUseable()) {
|
||||
continue;
|
||||
}
|
||||
@@ -2006,33 +1977,18 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
return sanitizedRequest;
|
||||
}
|
||||
|
||||
private void checkPackageName(String packageName) {
|
||||
if (packageName == null) {
|
||||
throw new SecurityException("invalid package name: " + null);
|
||||
}
|
||||
int uid = Binder.getCallingUid();
|
||||
String[] packages = mPackageManager.getPackagesForUid(uid);
|
||||
if (packages == null) {
|
||||
throw new SecurityException("invalid UID " + uid);
|
||||
}
|
||||
for (String pkg : packages) {
|
||||
if (packageName.equals(pkg)) return;
|
||||
}
|
||||
throw new SecurityException("invalid package name: " + packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestLocationUpdates(LocationRequest request, ILocationListener listener,
|
||||
PendingIntent intent, String packageName, String featureId,
|
||||
String listenerIdentifier) {
|
||||
Objects.requireNonNull(listenerIdentifier);
|
||||
|
||||
enforceCallingOrSelfLocationPermission();
|
||||
enforceCallingOrSelfPackageName(packageName);
|
||||
|
||||
synchronized (mLock) {
|
||||
if (request == null) request = DEFAULT_LOCATION_REQUEST;
|
||||
checkPackageName(packageName);
|
||||
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
|
||||
checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
|
||||
request.getProvider());
|
||||
WorkSource workSource = request.getWorkSource();
|
||||
if (workSource != null && !workSource.isEmpty()) {
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
@@ -2139,7 +2095,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
@Override
|
||||
public void removeUpdates(ILocationListener listener, PendingIntent intent,
|
||||
String packageName) {
|
||||
checkPackageName(packageName);
|
||||
enforceCallingOrSelfPackageName(packageName);
|
||||
|
||||
int pid = Binder.getCallingPid();
|
||||
int uid = Binder.getCallingUid();
|
||||
@@ -2201,12 +2157,12 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
|
||||
@Override
|
||||
public Location getLastLocation(LocationRequest r, String packageName, String featureId) {
|
||||
enforceCallingOrSelfLocationPermission();
|
||||
enforceCallingOrSelfPackageName(packageName);
|
||||
|
||||
synchronized (mLock) {
|
||||
LocationRequest request = r != null ? r : DEFAULT_LOCATION_REQUEST;
|
||||
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
|
||||
checkPackageName(packageName);
|
||||
checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
|
||||
request.getProvider());
|
||||
// no need to sanitize this request, as only the provider name is used
|
||||
|
||||
final int pid = Binder.getCallingPid();
|
||||
@@ -2352,7 +2308,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
public boolean injectLocation(Location location) {
|
||||
mContext.enforceCallingPermission(android.Manifest.permission.LOCATION_HARDWARE,
|
||||
"Location Hardware permission not granted to inject location");
|
||||
mContext.enforceCallingPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
|
||||
mContext.enforceCallingPermission(ACCESS_FINE_LOCATION,
|
||||
"Access Fine Location permission not granted to inject Location");
|
||||
|
||||
synchronized (mLock) {
|
||||
@@ -2378,17 +2334,14 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
String packageName, String featureId, String listenerIdentifier) {
|
||||
Objects.requireNonNull(listenerIdentifier);
|
||||
|
||||
mContext.enforceCallingOrSelfPermission(ACCESS_FINE_LOCATION, null);
|
||||
enforceCallingOrSelfPackageName(packageName);
|
||||
|
||||
if (request == null) request = DEFAULT_LOCATION_REQUEST;
|
||||
int allowedResolutionLevel = getCallerAllowedResolutionLevel();
|
||||
checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
|
||||
if (intent == null) {
|
||||
throw new IllegalArgumentException("invalid pending intent: " + null);
|
||||
}
|
||||
checkPackageName(packageName);
|
||||
synchronized (mLock) {
|
||||
checkResolutionLevelIsSufficientForProviderUseLocked(allowedResolutionLevel,
|
||||
request.getProvider());
|
||||
}
|
||||
// Require that caller can manage given document
|
||||
boolean callerHasLocationHardwarePermission =
|
||||
mContext.checkCallingPermission(android.Manifest.permission.LOCATION_HARDWARE)
|
||||
@@ -2434,7 +2387,7 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
if (intent == null) {
|
||||
throw new IllegalArgumentException("invalid pending intent: " + null);
|
||||
}
|
||||
checkPackageName(packageName);
|
||||
enforceCallingOrSelfPackageName(packageName);
|
||||
|
||||
if (D) Log.d(TAG, "removeGeofence: " + geofence + " " + intent);
|
||||
|
||||
@@ -2521,36 +2474,30 @@ public class LocationManagerService extends ILocationManager.Stub {
|
||||
|
||||
@Override
|
||||
public boolean sendExtraCommand(String providerName, String command, Bundle extras) {
|
||||
if (providerName == null) {
|
||||
// throw NullPointerException to remain compatible with previous implementation
|
||||
throw new NullPointerException();
|
||||
}
|
||||
Objects.requireNonNull(providerName);
|
||||
Objects.requireNonNull(command);
|
||||
|
||||
mContext.enforceCallingOrSelfPermission(
|
||||
Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS, null);
|
||||
enforceCallingOrSelfLocationPermission();
|
||||
|
||||
synchronized (mLock) {
|
||||
checkResolutionLevelIsSufficientForProviderUseLocked(getCallerAllowedResolutionLevel(),
|
||||
providerName);
|
||||
mLocationUsageLogger.logLocationApiUsage(
|
||||
LocationStatsEnums.USAGE_STARTED,
|
||||
LocationStatsEnums.API_SEND_EXTRA_COMMAND,
|
||||
providerName);
|
||||
|
||||
mLocationUsageLogger.logLocationApiUsage(
|
||||
LocationStatsEnums.USAGE_STARTED,
|
||||
LocationStatsEnums.API_SEND_EXTRA_COMMAND,
|
||||
providerName);
|
||||
|
||||
LocationProviderManager manager = getLocationProviderManager(providerName);
|
||||
if (manager != null) {
|
||||
manager.sendExtraCommand(Binder.getCallingUid(), Binder.getCallingPid(), command,
|
||||
extras);
|
||||
}
|
||||
|
||||
mLocationUsageLogger.logLocationApiUsage(
|
||||
LocationStatsEnums.USAGE_ENDED,
|
||||
LocationStatsEnums.API_SEND_EXTRA_COMMAND,
|
||||
providerName);
|
||||
|
||||
return true;
|
||||
LocationProviderManager manager = getLocationProviderManager(providerName);
|
||||
if (manager != null) {
|
||||
manager.sendExtraCommand(Binder.getCallingUid(), Binder.getCallingPid(), command,
|
||||
extras);
|
||||
}
|
||||
|
||||
mLocationUsageLogger.logLocationApiUsage(
|
||||
LocationStatsEnums.USAGE_ENDED,
|
||||
LocationStatsEnums.API_SEND_EXTRA_COMMAND,
|
||||
providerName);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user