diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 802b7d511bb96..0f9c1600523d1 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -145,6 +145,7 @@ package android { field public static final String KILL_UID = "android.permission.KILL_UID"; field public static final String LAUNCH_DEVICE_MANAGER_SETUP = "android.permission.LAUNCH_DEVICE_MANAGER_SETUP"; field public static final String LOCAL_MAC_ADDRESS = "android.permission.LOCAL_MAC_ADDRESS"; + field public static final String LOCATION_BYPASS = "android.permission.LOCATION_BYPASS"; field public static final String LOCK_DEVICE = "android.permission.LOCK_DEVICE"; field public static final String LOOP_RADIO = "android.permission.LOOP_RADIO"; field public static final String MANAGE_ACCESSIBILITY = "android.permission.MANAGE_ACCESSIBILITY"; @@ -5342,9 +5343,9 @@ package android.location { ctor public LastLocationRequest.Builder(); ctor public LastLocationRequest.Builder(@NonNull android.location.LastLocationRequest); method @NonNull public android.location.LastLocationRequest build(); - method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LastLocationRequest.Builder setAdasGnssBypass(boolean); + method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.WRITE_SECURE_SETTINGS, android.Manifest.permission.LOCATION_BYPASS}) public android.location.LastLocationRequest.Builder setAdasGnssBypass(boolean); method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LastLocationRequest.Builder setHiddenFromAppOps(boolean); - method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LastLocationRequest.Builder setLocationSettingsIgnored(boolean); + method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.WRITE_SECURE_SETTINGS, android.Manifest.permission.LOCATION_BYPASS}) public android.location.LastLocationRequest.Builder setLocationSettingsIgnored(boolean); } public class Location implements android.os.Parcelable { @@ -5373,7 +5374,7 @@ package android.location { method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull java.util.concurrent.Executor, @NonNull android.location.LocationListener); method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@Nullable android.location.LocationRequest, @NonNull android.app.PendingIntent); - method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setAdasGnssLocationEnabled(boolean); + method @RequiresPermission(anyOf={android.Manifest.permission.WRITE_SECURE_SETTINGS, android.Manifest.permission.LOCATION_BYPASS}) public void setAdasGnssLocationEnabled(boolean); method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackage(@Nullable String); method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackageEnabled(boolean); method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle); @@ -5406,7 +5407,7 @@ package android.location { method @Deprecated @NonNull public android.location.LocationRequest setFastestInterval(long); method @Deprecated public void setHideFromAppOps(boolean); method @Deprecated @NonNull public android.location.LocationRequest setInterval(long); - method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest setLocationSettingsIgnored(boolean); + method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.WRITE_SECURE_SETTINGS, android.Manifest.permission.LOCATION_BYPASS}) public android.location.LocationRequest setLocationSettingsIgnored(boolean); method @Deprecated @NonNull public android.location.LocationRequest setLowPowerMode(boolean); method @Deprecated @NonNull public android.location.LocationRequest setNumUpdates(int); method @Deprecated @NonNull public android.location.LocationRequest setProvider(@NonNull String); @@ -5422,9 +5423,9 @@ package android.location { } public static final class LocationRequest.Builder { - method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest.Builder setAdasGnssBypass(boolean); + method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.WRITE_SECURE_SETTINGS, android.Manifest.permission.LOCATION_BYPASS}) public android.location.LocationRequest.Builder setAdasGnssBypass(boolean); method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS) public android.location.LocationRequest.Builder setHiddenFromAppOps(boolean); - method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean); + method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.WRITE_SECURE_SETTINGS, android.Manifest.permission.LOCATION_BYPASS}) public android.location.LocationRequest.Builder setLocationSettingsIgnored(boolean); method @NonNull @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public android.location.LocationRequest.Builder setLowPower(boolean); method @NonNull @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public android.location.LocationRequest.Builder setWorkSource(@Nullable android.os.WorkSource); } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index a0e426db0e103..d8592e530a319 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1143,6 +1143,15 @@ android:description="@string/permdesc_accessBackgroundLocation" android:protectionLevel="dangerous|instant" /> + + + diff --git a/location/java/android/location/LastLocationRequest.java b/location/java/android/location/LastLocationRequest.java index 73c5c826584f6..fe0a14f37cb62 100644 --- a/location/java/android/location/LastLocationRequest.java +++ b/location/java/android/location/LastLocationRequest.java @@ -16,6 +16,9 @@ package android.location; +import static android.Manifest.permission.LOCATION_BYPASS; +import static android.Manifest.permission.WRITE_SECURE_SETTINGS; + import android.Manifest; import android.annotation.NonNull; import android.annotation.RequiresPermission; @@ -220,8 +223,9 @@ public final class LastLocationRequest implements Parcelable { * * @hide */ + // TODO: remove WRITE_SECURE_SETTINGS. @SystemApi - @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) + @RequiresPermission(anyOf = {WRITE_SECURE_SETTINGS, LOCATION_BYPASS}) public @NonNull LastLocationRequest.Builder setAdasGnssBypass(boolean adasGnssBypass) { mAdasGnssBypass = adasGnssBypass; return this; @@ -238,8 +242,9 @@ public final class LastLocationRequest implements Parcelable { * * @hide */ + // TODO: remove WRITE_SECURE_SETTINGS. @SystemApi - @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) + @RequiresPermission(anyOf = {WRITE_SECURE_SETTINGS, LOCATION_BYPASS}) public @NonNull Builder setLocationSettingsIgnored(boolean locationSettingsIgnored) { mLocationSettingsIgnored = locationSettingsIgnored; return this; diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java index d275628f6e24c..59c989b7f01ef 100644 --- a/location/java/android/location/LocationManager.java +++ b/location/java/android/location/LocationManager.java @@ -18,6 +18,7 @@ package android.location; import static android.Manifest.permission.ACCESS_COARSE_LOCATION; import static android.Manifest.permission.ACCESS_FINE_LOCATION; +import static android.Manifest.permission.LOCATION_BYPASS; import static android.Manifest.permission.LOCATION_HARDWARE; import static android.Manifest.permission.WRITE_SECURE_SETTINGS; import static android.location.LocationRequest.createFromDeprecatedCriteria; @@ -678,8 +679,9 @@ public class LocationManager { * * @hide */ + // TODO: remove WRITE_SECURE_SETTINGS. @SystemApi - @RequiresPermission(WRITE_SECURE_SETTINGS) + @RequiresPermission(anyOf = {WRITE_SECURE_SETTINGS, LOCATION_BYPASS}) public void setAdasGnssLocationEnabled(boolean enabled) { try { mService.setAdasGnssLocationEnabledForUser(enabled, mContext.getUser().getIdentifier()); diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java index 587222a4df43f..59f4f5e8c19ed 100644 --- a/location/java/android/location/LocationRequest.java +++ b/location/java/android/location/LocationRequest.java @@ -16,6 +16,9 @@ package android.location; +import static android.Manifest.permission.LOCATION_BYPASS; +import static android.Manifest.permission.WRITE_SECURE_SETTINGS; + import static java.lang.Math.max; import static java.lang.Math.min; @@ -662,9 +665,10 @@ public final class LocationRequest implements Parcelable { * @hide * @deprecated LocationRequests should be treated as immutable. */ + // TODO: remove WRITE_SECURE_SETTINGS. @SystemApi @Deprecated - @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) + @RequiresPermission(anyOf = {WRITE_SECURE_SETTINGS, LOCATION_BYPASS}) public @NonNull LocationRequest setLocationSettingsIgnored(boolean locationSettingsIgnored) { mBypass = locationSettingsIgnored; return this; @@ -1132,8 +1136,9 @@ public final class LocationRequest implements Parcelable { * * @hide */ + // TODO: remove WRITE_SECURE_SETTINGS @SystemApi - @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) + @RequiresPermission(anyOf = {WRITE_SECURE_SETTINGS, LOCATION_BYPASS}) public @NonNull Builder setAdasGnssBypass(boolean adasGnssBypass) { mAdasGnssBypass = adasGnssBypass; return this; @@ -1150,8 +1155,9 @@ public final class LocationRequest implements Parcelable { * * @hide */ + // TODO: remove WRITE_SECURE_SETTINGS @SystemApi - @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS) + @RequiresPermission(anyOf = {WRITE_SECURE_SETTINGS, LOCATION_BYPASS}) public @NonNull Builder setLocationSettingsIgnored(boolean locationSettingsIgnored) { mBypass = locationSettingsIgnored; return this; diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java index aa1fa9ba12211..0c3f9f0e26c69 100644 --- a/services/core/java/com/android/server/location/LocationManagerService.java +++ b/services/core/java/com/android/server/location/LocationManagerService.java @@ -17,6 +17,7 @@ package com.android.server.location; import static android.Manifest.permission.ACCESS_FINE_LOCATION; +import static android.Manifest.permission.WRITE_SECURE_SETTINGS; 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; @@ -829,16 +830,12 @@ public class LocationManagerService extends ILocationManager.Stub implements "only verified adas packages may use adas gnss bypass requests"); } if (!isLocationProvider) { - mContext.enforceCallingOrSelfPermission( - permission.WRITE_SECURE_SETTINGS, - "adas gnss bypass requires " + permission.WRITE_SECURE_SETTINGS); + LocationPermissions.enforceCallingOrSelfBypassPermission(mContext); } } if (request.isLocationSettingsIgnored()) { if (!isLocationProvider) { - mContext.enforceCallingOrSelfPermission( - permission.WRITE_SECURE_SETTINGS, - "ignoring location settings requires " + permission.WRITE_SECURE_SETTINGS); + LocationPermissions.enforceCallingOrSelfBypassPermission(mContext); } } @@ -933,16 +930,12 @@ public class LocationManagerService extends ILocationManager.Stub implements "only verified adas packages may use adas gnss bypass requests"); } if (!isLocationProvider) { - mContext.enforceCallingOrSelfPermission( - permission.WRITE_SECURE_SETTINGS, - "adas gnss bypass requires " + permission.WRITE_SECURE_SETTINGS); + LocationPermissions.enforceCallingOrSelfBypassPermission(mContext); } } if (request.isLocationSettingsIgnored()) { if (!isLocationProvider) { - mContext.enforceCallingOrSelfPermission( - permission.WRITE_SECURE_SETTINGS, - "ignoring location settings requires " + permission.WRITE_SECURE_SETTINGS); + LocationPermissions.enforceCallingOrSelfBypassPermission(mContext); } } @@ -1202,7 +1195,7 @@ public class LocationManagerService extends ILocationManager.Stub implements userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false, "setLocationEnabledForUser", null); - mContext.enforceCallingOrSelfPermission(permission.WRITE_SECURE_SETTINGS, null); + mContext.enforceCallingOrSelfPermission(WRITE_SECURE_SETTINGS, null); LocationManager.invalidateLocalLocationEnabledCaches(); mInjector.getSettingsHelper().setLocationEnabled(enabled, userId); @@ -1220,7 +1213,7 @@ public class LocationManagerService extends ILocationManager.Stub implements userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, false, false, "setAdasGnssLocationEnabledForUser", null); - mContext.enforceCallingOrSelfPermission(permission.WRITE_SECURE_SETTINGS, null); + LocationPermissions.enforceCallingOrSelfBypassPermission(mContext); mInjector.getLocationSettings().updateUserSettings(userId, settings -> settings.withAdasGnssLocationEnabled(enabled)); diff --git a/services/core/java/com/android/server/location/LocationPermissions.java b/services/core/java/com/android/server/location/LocationPermissions.java index 7528f8b6ea640..be702d906d3b3 100644 --- a/services/core/java/com/android/server/location/LocationPermissions.java +++ b/services/core/java/com/android/server/location/LocationPermissions.java @@ -18,6 +18,8 @@ package com.android.server.location; import static android.Manifest.permission.ACCESS_COARSE_LOCATION; import static android.Manifest.permission.ACCESS_FINE_LOCATION; +import static android.Manifest.permission.LOCATION_BYPASS; +import static android.Manifest.permission.WRITE_SECURE_SETTINGS; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import android.annotation.IntDef; @@ -120,6 +122,29 @@ public final class LocationPermissions { } } + /** + * Throws a security exception if the caller does not hold the required bypass permissions. + */ + public static void enforceCallingOrSelfBypassPermission(Context context) { + enforceBypassPermission(context, Binder.getCallingUid(), Binder.getCallingPid()); + } + + /** + * Throws a security exception if the given uid/pid does not hold the required bypass + * perissions. + */ + public static void enforceBypassPermission(Context context, int uid, int pid) { + if (context.checkPermission(WRITE_SECURE_SETTINGS, pid, uid) == PERMISSION_GRANTED) { + // TODO: disallow WRITE_SECURE_SETTINGS permission. + return; + } + if (context.checkPermission(LOCATION_BYPASS, pid, uid) == PERMISSION_GRANTED) { + return; + } + throw new SecurityException("uid" + uid + " does not have " + LOCATION_BYPASS + + "or " + WRITE_SECURE_SETTINGS + "."); + } + /** * Returns false if the caller does not hold the required location permissions. */