Merge "Block immutable PIs from location APIs"

This commit is contained in:
TreeHugger Robot
2020-11-04 20:16:15 +00:00
committed by Android (Google) Code Review
3 changed files with 66 additions and 42 deletions

View File

@@ -76,18 +76,27 @@ import java.util.function.Consumer;
* obtain periodic updates of the device's geographical location, or to be notified when the device
* enters the proximity of a given geographical location.
*
* <p class="note">Unless noted, all Location API methods require the {@link
* android.Manifest.permission#ACCESS_COARSE_LOCATION} or {@link
* android.Manifest.permission#ACCESS_FINE_LOCATION} permissions. If your application only has the
* coarse permission then it will not have access to fine location providers. Other providers will
* still return location results, but the exact location will be obfuscated to a coarse level of
* accuracy.
* <p class="note">Unless otherwise noted, all Location API methods require the
* {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} or
* {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permissions. If your application only
* has the coarse permission then providers will still return location results, but the exact
* location will be obfuscated to a coarse level of accuracy.
*/
@SuppressWarnings({"deprecation"})
@SystemService(Context.LOCATION_SERVICE)
@RequiresFeature(PackageManager.FEATURE_LOCATION)
public class LocationManager {
/**
* For apps targeting Android S and above, immutable PendingIntents passed into location APIs
* will generate an IllegalArgumentException.
*
* @hide
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
public static final long BLOCK_IMMUTABLE_PENDING_INTENTS = 171317480L;
/**
* For apps targeting Android S and above, LocationRequest system APIs may not be used with
* PendingIntent location requests.
@@ -96,7 +105,7 @@ public class LocationManager {
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
public static final long PREVENT_PENDING_INTENT_SYSTEM_API_USAGE = 169887240L;
public static final long BLOCK_PENDING_INTENT_SYSTEM_API_USAGE = 169887240L;
/**
* For apps targeting Android S and above, location clients may receive historical locations
@@ -116,7 +125,7 @@ public class LocationManager {
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
private static final long GET_PROVIDER_SECURITY_EXCEPTIONS = 150935354L;
public static final long GET_PROVIDER_SECURITY_EXCEPTIONS = 150935354L;
/**
* For apps targeting Android K and above, supplied {@link PendingIntent}s must be targeted to a
@@ -126,7 +135,7 @@ public class LocationManager {
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
private static final long TARGETED_PENDING_INTENT = 148963590L;
public static final long BLOCK_UNTARGETED_PENDING_INTENTS = 148963590L;
/**
* For apps targeting Android K and above, incomplete locations may not be passed to
@@ -136,7 +145,7 @@ public class LocationManager {
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
private static final long INCOMPLETE_LOCATION = 148964793L;
public static final long BLOCK_INCOMPLETE_LOCATIONS = 148964793L;
/**
* For apps targeting Android S and above, all {@link GpsStatus} API usage must be replaced with
@@ -146,7 +155,7 @@ public class LocationManager {
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
private static final long GPS_STATUS_USAGE = 144027538L;
public static final long BLOCK_GPS_STATUS_USAGE = 144027538L;
/**
* Name of the network location provider.
@@ -1372,11 +1381,16 @@ public class LocationManager {
Preconditions.checkArgument(locationRequest != null, "invalid null location request");
Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent");
if (Compatibility.isChangeEnabled(TARGETED_PENDING_INTENT)) {
if (Compatibility.isChangeEnabled(BLOCK_UNTARGETED_PENDING_INTENTS)) {
Preconditions.checkArgument(pendingIntent.isTargetedToPackage(),
"pending intent must be targeted to a package");
}
if (Compatibility.isChangeEnabled(BLOCK_IMMUTABLE_PENDING_INTENTS)) {
Preconditions.checkArgument(!pendingIntent.isImmutable(),
"pending intent must be mutable");
}
try {
mService.registerLocationPendingIntent(provider, locationRequest, pendingIntent,
mContext.getPackageName(), mContext.getAttributionTag());
@@ -1729,7 +1743,7 @@ public class LocationManager {
Preconditions.checkArgument(provider != null, "invalid null provider");
Preconditions.checkArgument(location != null, "invalid null location");
if (Compatibility.isChangeEnabled(INCOMPLETE_LOCATION)) {
if (Compatibility.isChangeEnabled(BLOCK_INCOMPLETE_LOCATIONS)) {
Preconditions.checkArgument(location.isComplete(),
"incomplete location object, missing timestamp or accuracy?");
} else {
@@ -1821,29 +1835,38 @@ public class LocationManager {
* {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}. From API version 17 and onwards,
* this method requires {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permission.
*
* @param latitude the latitude of the central point of the alert region
* @param longitude the longitude of the central point of the alert region
* @param radius the radius of the central point of the alert region in meters
* @param expiration expiration realtime for this proximity alert in milliseconds, or -1 to
* indicate no expiration
* @param intent a {@link PendingIntent} that will sent when entry to or exit from the alert
* region is detected
* @param latitude the latitude of the central point of the alert region
* @param longitude the longitude of the central point of the alert region
* @param radius the radius of the central point of the alert region in meters
* @param expiration expiration realtime for this proximity alert in milliseconds, or -1 to
* indicate no expiration
* @param pendingIntent a {@link PendingIntent} that will sent when entry to or exit from the
* alert region is detected
* @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
* permission is not present
*/
@RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
public void addProximityAlert(double latitude, double longitude, float radius, long expiration,
@NonNull PendingIntent intent) {
Preconditions.checkArgument(intent != null, "invalid null pending intent");
if (Compatibility.isChangeEnabled(TARGETED_PENDING_INTENT)) {
Preconditions.checkArgument(intent.isTargetedToPackage(),
@NonNull PendingIntent pendingIntent) {
Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent");
if (Compatibility.isChangeEnabled(BLOCK_UNTARGETED_PENDING_INTENTS)) {
Preconditions.checkArgument(pendingIntent.isTargetedToPackage(),
"pending intent must be targeted to a package");
}
if (expiration < 0) expiration = Long.MAX_VALUE;
if (Compatibility.isChangeEnabled(BLOCK_IMMUTABLE_PENDING_INTENTS)) {
Preconditions.checkArgument(!pendingIntent.isImmutable(),
"pending intent must be mutable");
}
if (expiration < 0) {
expiration = Long.MAX_VALUE;
}
try {
Geofence fence = Geofence.createCircle(latitude, longitude, radius, expiration);
mService.requestGeofence(fence, intent, mContext.getPackageName(),
mService.requestGeofence(fence, pendingIntent, mContext.getPackageName(),
mContext.getAttributionTag());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -1941,7 +1964,7 @@ public class LocationManager {
@Deprecated
@RequiresPermission(ACCESS_FINE_LOCATION)
public @Nullable GpsStatus getGpsStatus(@Nullable GpsStatus status) {
if (Compatibility.isChangeEnabled(GPS_STATUS_USAGE)) {
if (Compatibility.isChangeEnabled(BLOCK_GPS_STATUS_USAGE)) {
throw new UnsupportedOperationException(
"GpsStatus APIs not supported, please use GnssStatus APIs instead");
}
@@ -1976,7 +1999,7 @@ public class LocationManager {
@Deprecated
@RequiresPermission(ACCESS_FINE_LOCATION)
public boolean addGpsStatusListener(GpsStatus.Listener listener) {
if (Compatibility.isChangeEnabled(GPS_STATUS_USAGE)) {
if (Compatibility.isChangeEnabled(BLOCK_GPS_STATUS_USAGE)) {
throw new UnsupportedOperationException(
"GpsStatus APIs not supported, please use GnssStatus APIs instead");
}
@@ -1996,7 +2019,7 @@ public class LocationManager {
*/
@Deprecated
public void removeGpsStatusListener(GpsStatus.Listener listener) {
if (Compatibility.isChangeEnabled(GPS_STATUS_USAGE)) {
if (Compatibility.isChangeEnabled(BLOCK_GPS_STATUS_USAGE)) {
throw new UnsupportedOperationException(
"GpsStatus APIs not supported, please use GnssStatus APIs instead");
}

View File

@@ -21,10 +21,10 @@ import static android.app.compat.CompatChanges.isChangeEnabled;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.location.LocationManager.BLOCK_PENDING_INTENT_SYSTEM_API_USAGE;
import static android.location.LocationManager.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationManager.NETWORK_PROVIDER;
import static android.location.LocationManager.PREVENT_PENDING_INTENT_SYSTEM_API_USAGE;
import static android.location.LocationRequest.LOW_POWER_EXCEPTIONS;
import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
@@ -597,14 +597,15 @@ public class LocationManagerService extends ILocationManager.Stub {
// simplest to ensure these apis are simply never set for pending intent requests. the same
// does not apply for listener requests since those will have the process (including the
// listener) killed on permission removal
boolean usesSystemApi = request.isLowPower()
|| request.isHiddenFromAppOps()
|| request.isLocationSettingsIgnored()
|| !request.getWorkSource().isEmpty();
if (usesSystemApi
&& isChangeEnabled(PREVENT_PENDING_INTENT_SYSTEM_API_USAGE, identity.getUid())) {
throw new SecurityException(
"PendingIntent location requests may not use system APIs: " + request);
if (isChangeEnabled(BLOCK_PENDING_INTENT_SYSTEM_API_USAGE, identity.getUid())) {
boolean usesSystemApi = request.isLowPower()
|| request.isHiddenFromAppOps()
|| request.isLocationSettingsIgnored()
|| !request.getWorkSource().isEmpty();
if (usesSystemApi) {
throw new SecurityException(
"PendingIntent location requests may not use system APIs: " + request);
}
}
request = validateLocationRequest(request, identity);

View File

@@ -296,15 +296,15 @@ public class GeofenceManager extends
@Nullable String attributionTag) {
LocationPermissions.enforceCallingOrSelfLocationPermission(mContext, PERMISSION_FINE);
CallerIdentity callerIdentity = CallerIdentity.fromBinder(mContext, packageName,
CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName,
attributionTag, AppOpsManager.toReceiverId(pendingIntent));
final long identity = Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
try {
putRegistration(new GeofenceKey(pendingIntent, geofence),
new GeofenceRegistration(geofence, callerIdentity, pendingIntent));
new GeofenceRegistration(geofence, identity, pendingIntent));
} finally {
Binder.restoreCallingIdentity(identity);
Binder.restoreCallingIdentity(ident);
}
}