Merge "Adds LOCATION_BYPASS permission."
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 9da2abb..6a50670 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -146,6 +146,7 @@
     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";
@@ -5538,9 +5539,9 @@
     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 {
@@ -5569,7 +5570,7 @@
     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);
@@ -5602,7 +5603,7 @@
     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);
@@ -5618,9 +5619,9 @@
   }
 
   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 0c8c7f2..6e54197 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1145,6 +1145,15 @@
         android:description="@string/permdesc_accessBackgroundLocation"
         android:protectionLevel="dangerous|instant" />
 
+    <!-- Allows an application (emergency or advanced driver-assistance app) to bypass
+    location settings.
+         <p>Not for use by third-party applications.
+         @SystemApi
+         @hide
+    -->
+    <permission android:name="android.permission.LOCATION_BYPASS"
+                android:protectionLevel="signature|privileged"/>
+
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the call log                                 -->
     <!-- ====================================================================== -->
diff --git a/location/java/android/location/LastLocationRequest.java b/location/java/android/location/LastLocationRequest.java
index 73c5c82..fe0a14f 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 @@
          *
          * @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 @@
          *
          * @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 d275628..59c989b 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -18,6 +18,7 @@
 
 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 @@
      *
      * @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 587222a..59f4f5e 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 @@
      * @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 @@
          *
          * @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 @@
          *
          * @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 aa1fa9b..0c3f9f0 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 @@
                         "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 @@
                         "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 @@
         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 @@
         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 7528f8b..be702d9 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 @@
 
 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;
@@ -121,6 +123,29 @@
     }
 
     /**
+     * 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.
      */
     public static boolean checkCallingOrSelfLocationPermission(Context context,