Surface "neverForLocation" through public API.

Since developers can declare the "neverForLocation" flag in their
manifest as public API, we should also offer a way to inspect the
value that we parsed from the manifest.  We do this by surfacing it
through the existing PackageInfo.requestedPermissionsFlags field.

This also means we can remove the PackageManagerInternal API, since
interested parties can now check PackageInfo directly.

Fix a potential security issue by only accepting flags from manifest
when the application is targeting a modern enough SDK.

Bug: 181812281
Test: atest CtsContentTestCases:PackageManagerTest
Test: atest FrameworksServicesTests:PackageParserTest
Test: atest com.android.server.pm.parsing
Change-Id: I877768c06ee15281f3334794034f4af563e74569
diff --git a/core/api/current.txt b/core/api/current.txt
index ba5f623..cb20f4b 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1581,6 +1581,7 @@
     field public static final int useLevel = 16843167; // 0x101019f
     field public static final int userVisible = 16843409; // 0x1010291
     field public static final int usesCleartextTraffic = 16844012; // 0x10104ec
+    field public static final int usesPermissionFlags = 16844356; // 0x1010644
     field public static final int value = 16842788; // 0x1010024
     field public static final int valueFrom = 16843486; // 0x10102de
     field public static final int valueTo = 16843487; // 0x10102df
@@ -12168,6 +12169,7 @@
     field public static final int INSTALL_LOCATION_INTERNAL_ONLY = 1; // 0x1
     field public static final int INSTALL_LOCATION_PREFER_EXTERNAL = 2; // 0x2
     field public static final int REQUESTED_PERMISSION_GRANTED = 2; // 0x2
+    field public static final int REQUESTED_PERMISSION_NEVER_FOR_LOCATION = 65536; // 0x10000
     field public android.content.pm.ActivityInfo[] activities;
     field public android.content.pm.ApplicationInfo applicationInfo;
     field @Nullable public android.content.pm.Attribution[] attributions;
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index e8ef077..0462a4b 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -232,13 +232,23 @@
      *
      * @removed We do not support required permissions.
      */
-    public static final int REQUESTED_PERMISSION_REQUIRED = 1<<0;
+    public static final int REQUESTED_PERMISSION_REQUIRED = 0x00000001;
 
     /**
      * Flag for {@link #requestedPermissionsFlags}: the requested permission
      * is currently granted to the application.
      */
-    public static final int REQUESTED_PERMISSION_GRANTED = 1<<1;
+    public static final int REQUESTED_PERMISSION_GRANTED = 0x00000002;
+
+    /**
+     * Flag for {@link #requestedPermissionsFlags}: the requested permission has
+     * declared {@code neverForLocation} in their manifest as a strong assertion
+     * by a developer that they will never use this permission to derive the
+     * physical location of the device, regardless of
+     * {@link android.Manifest.permission#ACCESS_FINE_LOCATION} and/or
+     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION} being granted.
+     */
+    public static final int REQUESTED_PERMISSION_NEVER_FOR_LOCATION = 0x00010000;
 
     /**
      * Array of all signatures read from the package file. This is only filled
diff --git a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
index fdd2c2a..e0052da 100644
--- a/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
+++ b/core/java/android/content/pm/parsing/PackageInfoWithoutStateUtils.java
@@ -52,6 +52,7 @@
 import android.content.pm.parsing.component.ParsedPermissionGroup;
 import android.content.pm.parsing.component.ParsedProvider;
 import android.content.pm.parsing.component.ParsedService;
+import android.content.pm.parsing.component.ParsedUsesPermission;
 import android.os.Environment;
 import android.os.UserHandle;
 
@@ -61,6 +62,7 @@
 
 import java.io.File;
 import java.util.Collections;
+import java.util.List;
 import java.util.Set;
 
 /** @hide **/
@@ -264,17 +266,26 @@
                             flags);
                 }
             }
-            size = pkg.getRequestedPermissions().size();
+            final List<ParsedUsesPermission> usesPermissions = pkg.getUsesPermissions();
+            size = usesPermissions.size();
             if (size > 0) {
                 pi.requestedPermissions = new String[size];
                 pi.requestedPermissionsFlags = new int[size];
                 for (int i = 0; i < size; i++) {
-                    final String perm = pkg.getRequestedPermissions().get(i);
-                    pi.requestedPermissions[i] = perm;
+                    final ParsedUsesPermission usesPermission = usesPermissions.get(i);
+                    pi.requestedPermissions[i] = usesPermission.name;
                     // The notion of required permissions is deprecated but for compatibility.
-                    pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_REQUIRED;
-                    if (grantedPermissions != null && grantedPermissions.contains(perm)) {
-                        pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_GRANTED;
+                    pi.requestedPermissionsFlags[i] |=
+                            PackageInfo.REQUESTED_PERMISSION_REQUIRED;
+                    if (grantedPermissions != null
+                            && grantedPermissions.contains(usesPermission.name)) {
+                        pi.requestedPermissionsFlags[i] |=
+                                PackageInfo.REQUESTED_PERMISSION_GRANTED;
+                    }
+                    if ((usesPermission.usesPermissionFlags
+                            & ParsedUsesPermission.FLAG_NEVER_FOR_LOCATION) != 0) {
+                        pi.requestedPermissionsFlags[i] |=
+                                PackageInfo.REQUESTED_PERMISSION_NEVER_FOR_LOCATION;
                     }
                 }
             }
diff --git a/core/java/android/content/pm/parsing/component/ParsedUsesPermission.java b/core/java/android/content/pm/parsing/component/ParsedUsesPermission.java
index b9c2e36..adf8da0 100644
--- a/core/java/android/content/pm/parsing/component/ParsedUsesPermission.java
+++ b/core/java/android/content/pm/parsing/component/ParsedUsesPermission.java
@@ -20,6 +20,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.content.pm.PackageInfo;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -44,7 +45,8 @@
      * to derive the physical location of the device, regardless of
      * ACCESS_FINE_LOCATION and/or ACCESS_COARSE_LOCATION being granted.
      */
-    public static final int FLAG_NEVER_FOR_LOCATION = 0x1;
+    public static final int FLAG_NEVER_FOR_LOCATION =
+            PackageInfo.REQUESTED_PERMISSION_NEVER_FOR_LOCATION;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 0318be7..140163e 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2063,13 +2063,14 @@
         requested.  If it does support the feature, it will be as if the manifest didn't
         request it at all. -->
         <attr name="requiredNotFeature" format="string" />
-        <!-- Optional: set of flags that should apply to this permission request. -->
+        <!-- Optional: set of flags that should apply to this permission request. Note that
+             these flags start at 0x4 to match PackageInfo.requestedPermissionsFlags. -->
         <attr name="usesPermissionFlags">
             <!-- Strong assertion by a developer that they will never use this
                  permission to derive the physical location of the device, even
                  when the app has been granted the ACCESS_FINE_LOCATION and/or
                  ACCESS_COARSE_LOCATION permissions. -->
-            <flag name="neverForLocation" value="0x1" />
+            <flag name="neverForLocation" value="0x00010000" />
         </attr>
     </declare-styleable>
 
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 33cc89d..3e5fad8 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3091,6 +3091,7 @@
     <public name="isAccessibilityTool"/>
     <public name="attributionTags"/>
     <public name="suppressesSpellChecker" />
+    <public name="usesPermissionFlags" />
   </public-group>
 
   <public-group type="drawable" first-id="0x010800b5">
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index b089014..c295778 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -1141,12 +1141,4 @@
      */
     public abstract boolean isPackageFrozen(
             @NonNull String packageName, int callingUid, int userId);
-
-    /**
-     * Returns true if the given {@code packageName} has declared the
-     * {@code neverForLocation} flag in the {@code uses-permission} manifest tag
-     * where they request the given {@code permissionName}.
-     */
-    public abstract boolean isPackageUsesPermissionNeverForLocation(@NonNull String packageName,
-            @NonNull String permissionName);
 }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ff042c2..43eeb2a5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -27324,31 +27324,8 @@
             return PackageManagerService.this.getPackageStartability(
                     packageName, callingUid, userId) == PACKAGE_STARTABILITY_FROZEN;
         }
-
-        @Override
-        public boolean isPackageUsesPermissionNeverForLocation(@NonNull String packageName,
-                @NonNull String permissionName) {
-            Objects.requireNonNull(packageName);
-            Objects.requireNonNull(permissionName);
-            final AndroidPackage pkg;
-            synchronized (mLock) {
-                pkg = mPackages.get(packageName);
-            }
-            if (pkg == null) return false;
-            final List<ParsedUsesPermission> usesPermissions = pkg.getUsesPermissions();
-            final int size = usesPermissions.size();
-            for (int i = 0; i < size; i++) {
-                final ParsedUsesPermission usesPermission = usesPermissions.get(i);
-                if (Objects.equals(usesPermission.name, permissionName)) {
-                    return (usesPermission.usesPermissionFlags
-                            & ParsedUsesPermission.FLAG_NEVER_FOR_LOCATION) != 0;
-                }
-            }
-            return false;
-        }
     }
 
-
     @GuardedBy("mLock")
     private SparseArray<String> getAppsWithSharedUserIdsLocked() {
         final SparseArray<String> sharedUserIds = new SparseArray<>();