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

Commit c6183933 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Block immutable PIs from location APIs"

parents 281f5eea 0875bf8c
Loading
Loading
Loading
Loading
+52 −29
Original line number Original line Diff line number Diff line
@@ -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
 * obtain periodic updates of the device's geographical location, or to be notified when the device
 * enters the proximity of a given geographical location.
 * enters the proximity of a given geographical location.
 *
 *
 * <p class="note">Unless noted, all Location API methods require the {@link
 * <p class="note">Unless otherwise noted, all Location API methods require the
 * android.Manifest.permission#ACCESS_COARSE_LOCATION} or {@link
 * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} or
 * android.Manifest.permission#ACCESS_FINE_LOCATION} permissions. If your application only has the
 * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} permissions. If your application only
 * coarse permission then it will not have access to fine location providers. Other providers will
 * has the coarse permission then providers will still return location results, but the exact
 * still return location results, but the exact location will be obfuscated to a coarse level of
 * location will be obfuscated to a coarse level of accuracy.
 * accuracy.
 */
 */
@SuppressWarnings({"deprecation"})
@SuppressWarnings({"deprecation"})
@SystemService(Context.LOCATION_SERVICE)
@SystemService(Context.LOCATION_SERVICE)
@RequiresFeature(PackageManager.FEATURE_LOCATION)
@RequiresFeature(PackageManager.FEATURE_LOCATION)
public class LocationManager {
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
     * For apps targeting Android S and above, LocationRequest system APIs may not be used with
     * PendingIntent location requests.
     * PendingIntent location requests.
@@ -96,7 +105,7 @@ public class LocationManager {
     */
     */
    @ChangeId
    @ChangeId
    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
    @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
     * For apps targeting Android S and above, location clients may receive historical locations
@@ -116,7 +125,7 @@ public class LocationManager {
     */
     */
    @ChangeId
    @ChangeId
    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
    @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
     * For apps targeting Android K and above, supplied {@link PendingIntent}s must be targeted to a
@@ -126,7 +135,7 @@ public class LocationManager {
     */
     */
    @ChangeId
    @ChangeId
    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
    @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
     * For apps targeting Android K and above, incomplete locations may not be passed to
@@ -136,7 +145,7 @@ public class LocationManager {
     */
     */
    @ChangeId
    @ChangeId
    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.JELLY_BEAN)
    @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
     * For apps targeting Android S and above, all {@link GpsStatus} API usage must be replaced with
@@ -146,7 +155,7 @@ public class LocationManager {
     */
     */
    @ChangeId
    @ChangeId
    @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
    @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.
     * Name of the network location provider.
@@ -1372,11 +1381,16 @@ public class LocationManager {
        Preconditions.checkArgument(locationRequest != null, "invalid null location request");
        Preconditions.checkArgument(locationRequest != null, "invalid null location request");
        Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent");
        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(),
            Preconditions.checkArgument(pendingIntent.isTargetedToPackage(),
                    "pending intent must be targeted to a package");
                    "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 {
        try {
            mService.registerLocationPendingIntent(provider, locationRequest, pendingIntent,
            mService.registerLocationPendingIntent(provider, locationRequest, pendingIntent,
                    mContext.getPackageName(), mContext.getAttributionTag());
                    mContext.getPackageName(), mContext.getAttributionTag());
@@ -1729,7 +1743,7 @@ public class LocationManager {
        Preconditions.checkArgument(provider != null, "invalid null provider");
        Preconditions.checkArgument(provider != null, "invalid null provider");
        Preconditions.checkArgument(location != null, "invalid null location");
        Preconditions.checkArgument(location != null, "invalid null location");


        if (Compatibility.isChangeEnabled(INCOMPLETE_LOCATION)) {
        if (Compatibility.isChangeEnabled(BLOCK_INCOMPLETE_LOCATIONS)) {
            Preconditions.checkArgument(location.isComplete(),
            Preconditions.checkArgument(location.isComplete(),
                    "incomplete location object, missing timestamp or accuracy?");
                    "incomplete location object, missing timestamp or accuracy?");
        } else {
        } else {
@@ -1826,24 +1840,33 @@ public class LocationManager {
     * @param radius        the radius of the central point of the alert region in meters
     * @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
     * @param expiration    expiration realtime for this proximity alert in milliseconds, or -1 to
     *                      indicate no expiration
     *                      indicate no expiration
     * @param intent     a {@link PendingIntent} that will sent when entry to or exit from the alert
     * @param pendingIntent a {@link PendingIntent} that will sent when entry to or exit from the
     *                   region is detected
     *                      alert region is detected
     * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
     * @throws SecurityException if {@link android.Manifest.permission#ACCESS_FINE_LOCATION}
     *                           permission is not present
     *                           permission is not present
     */
     */
    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
    @RequiresPermission(anyOf = {ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION})
    public void addProximityAlert(double latitude, double longitude, float radius, long expiration,
    public void addProximityAlert(double latitude, double longitude, float radius, long expiration,
            @NonNull PendingIntent intent) {
            @NonNull PendingIntent pendingIntent) {
        Preconditions.checkArgument(intent != null, "invalid null pending intent");
        Preconditions.checkArgument(pendingIntent != null, "invalid null pending intent");
        if (Compatibility.isChangeEnabled(TARGETED_PENDING_INTENT)) {

            Preconditions.checkArgument(intent.isTargetedToPackage(),
        if (Compatibility.isChangeEnabled(BLOCK_UNTARGETED_PENDING_INTENTS)) {
            Preconditions.checkArgument(pendingIntent.isTargetedToPackage(),
                    "pending intent must be targeted to a package");
                    "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 {
        try {
            Geofence fence = Geofence.createCircle(latitude, longitude, radius, expiration);
            Geofence fence = Geofence.createCircle(latitude, longitude, radius, expiration);
            mService.requestGeofence(fence, intent, mContext.getPackageName(),
            mService.requestGeofence(fence, pendingIntent, mContext.getPackageName(),
                    mContext.getAttributionTag());
                    mContext.getAttributionTag());
        } catch (RemoteException e) {
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
            throw e.rethrowFromSystemServer();
@@ -1941,7 +1964,7 @@ public class LocationManager {
    @Deprecated
    @Deprecated
    @RequiresPermission(ACCESS_FINE_LOCATION)
    @RequiresPermission(ACCESS_FINE_LOCATION)
    public @Nullable GpsStatus getGpsStatus(@Nullable GpsStatus status) {
    public @Nullable GpsStatus getGpsStatus(@Nullable GpsStatus status) {
        if (Compatibility.isChangeEnabled(GPS_STATUS_USAGE)) {
        if (Compatibility.isChangeEnabled(BLOCK_GPS_STATUS_USAGE)) {
            throw new UnsupportedOperationException(
            throw new UnsupportedOperationException(
                    "GpsStatus APIs not supported, please use GnssStatus APIs instead");
                    "GpsStatus APIs not supported, please use GnssStatus APIs instead");
        }
        }
@@ -1976,7 +1999,7 @@ public class LocationManager {
    @Deprecated
    @Deprecated
    @RequiresPermission(ACCESS_FINE_LOCATION)
    @RequiresPermission(ACCESS_FINE_LOCATION)
    public boolean addGpsStatusListener(GpsStatus.Listener listener) {
    public boolean addGpsStatusListener(GpsStatus.Listener listener) {
        if (Compatibility.isChangeEnabled(GPS_STATUS_USAGE)) {
        if (Compatibility.isChangeEnabled(BLOCK_GPS_STATUS_USAGE)) {
            throw new UnsupportedOperationException(
            throw new UnsupportedOperationException(
                    "GpsStatus APIs not supported, please use GnssStatus APIs instead");
                    "GpsStatus APIs not supported, please use GnssStatus APIs instead");
        }
        }
@@ -1996,7 +2019,7 @@ public class LocationManager {
     */
     */
    @Deprecated
    @Deprecated
    public void removeGpsStatusListener(GpsStatus.Listener listener) {
    public void removeGpsStatusListener(GpsStatus.Listener listener) {
        if (Compatibility.isChangeEnabled(GPS_STATUS_USAGE)) {
        if (Compatibility.isChangeEnabled(BLOCK_GPS_STATUS_USAGE)) {
            throw new UnsupportedOperationException(
            throw new UnsupportedOperationException(
                    "GpsStatus APIs not supported, please use GnssStatus APIs instead");
                    "GpsStatus APIs not supported, please use GnssStatus APIs instead");
        }
        }
+10 −9
Original line number Original line Diff line number Diff line
@@ -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_DIRECT_BOOT_AWARE;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
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.FUSED_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationManager.GPS_PROVIDER;
import static android.location.LocationManager.NETWORK_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 android.location.LocationRequest.LOW_POWER_EXCEPTIONS;


import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
@@ -597,15 +597,16 @@ public class LocationManagerService extends ILocationManager.Stub {
        // simplest to ensure these apis are simply never set for pending intent requests. the same
        // 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
        // does not apply for listener requests since those will have the process (including the
        // listener) killed on permission removal
        // listener) killed on permission removal
        if (isChangeEnabled(BLOCK_PENDING_INTENT_SYSTEM_API_USAGE, identity.getUid())) {
            boolean usesSystemApi = request.isLowPower()
            boolean usesSystemApi = request.isLowPower()
                    || request.isHiddenFromAppOps()
                    || request.isHiddenFromAppOps()
                    || request.isLocationSettingsIgnored()
                    || request.isLocationSettingsIgnored()
                    || !request.getWorkSource().isEmpty();
                    || !request.getWorkSource().isEmpty();
        if (usesSystemApi
            if (usesSystemApi) {
                && isChangeEnabled(PREVENT_PENDING_INTENT_SYSTEM_API_USAGE, identity.getUid())) {
                throw new SecurityException(
                throw new SecurityException(
                        "PendingIntent location requests may not use system APIs: " + request);
                        "PendingIntent location requests may not use system APIs: " + request);
            }
            }
        }


        request = validateLocationRequest(request, identity);
        request = validateLocationRequest(request, identity);


+4 −4
Original line number Original line Diff line number Diff line
@@ -296,15 +296,15 @@ public class GeofenceManager extends
            @Nullable String attributionTag) {
            @Nullable String attributionTag) {
        LocationPermissions.enforceCallingOrSelfLocationPermission(mContext, PERMISSION_FINE);
        LocationPermissions.enforceCallingOrSelfLocationPermission(mContext, PERMISSION_FINE);


        CallerIdentity callerIdentity = CallerIdentity.fromBinder(mContext, packageName,
        CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName,
                attributionTag, AppOpsManager.toReceiverId(pendingIntent));
                attributionTag, AppOpsManager.toReceiverId(pendingIntent));


        final long identity = Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();
        try {
        try {
            putRegistration(new GeofenceKey(pendingIntent, geofence),
            putRegistration(new GeofenceKey(pendingIntent, geofence),
                    new GeofenceRegistration(geofence, callerIdentity, pendingIntent));
                    new GeofenceRegistration(geofence, identity, pendingIntent));
        } finally {
        } finally {
            Binder.restoreCallingIdentity(identity);
            Binder.restoreCallingIdentity(ident);
        }
        }
    }
    }