Add SystemFeaturesMetadata to framework

Use the SDK_FEATURE_COUNT metadata field to give a tighter bound
for the system feature IPC cache. We have to first re-declare
this in PackageManager such that it's visible to other (internal)
classes where it will be used, in this case, ApplicationPackageManager.

Bug: 375000483
Test: atest PackageManagerTest
Flag: EXEMPT refactor
Change-Id: Idfd4944381f0d0e8e4f3e8ba30b37c578545fe60
diff --git a/Android.bp b/Android.bp
index 94e5e33..d3e7e48 100644
--- a/Android.bp
+++ b/Android.bp
@@ -370,6 +370,7 @@
         "view-inspector-annotation-processor",
         "staledataclass-annotation-processor",
         "error_prone_android_framework",
+        "systemfeatures-metadata-processor",
     ],
     // Exports needed for staledataclass-annotation-processor, see b/139342589.
     javacflags: [
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0ed9c87..f4b7ca7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3112,6 +3112,16 @@
     public static final long MAXIMUM_VERIFICATION_TIMEOUT = 60*60*1000;
 
     /**
+     * As the generated feature count is useful for classes that may not be compiled in the same
+     * annotation processing unit as PackageManager, we redeclare it here for visibility.
+     *
+     * @hide
+     */
+    @VisibleForTesting
+    public static final int SDK_FEATURE_COUNT =
+            com.android.internal.pm.SystemFeaturesMetadata.SDK_FEATURE_COUNT;
+
+    /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: The device's
      * audio pipeline is low-latency, more suitable for audio applications sensitive to delays or
      * lag in sound input or output.
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTest.java b/core/tests/coretests/src/android/content/pm/PackageManagerTest.java
index 20421d1..d080ee7 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTest.java
@@ -24,6 +24,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class PackageManagerTest {
@@ -46,4 +49,25 @@
     public void testResolveInfoFlags() throws Exception {
         assertThat(PackageManager.ResolveInfoFlags.of(42L).getValue()).isEqualTo(42L);
     }
+
+    @Test
+    public void testSdkFeatureCount() throws Exception {
+        // Check to make sure the system feature `SdkConst` annotation processor yields sensible
+        // results. We don't care about the exactness, just that it's not pathologically wrong.
+        assertThat(PackageManager.SDK_FEATURE_COUNT).isGreaterThan(150);
+        assertThat(PackageManager.SDK_FEATURE_COUNT).isLessThan(500);
+        assertThat(PackageManager.SDK_FEATURE_COUNT)
+                .isWithin(50)
+                .of(getApproximateFeatureCountUsingReflection());
+    }
+
+    /* Return a ballpark estimate of the feature count using FEATURE_ field names. */
+    private static int getApproximateFeatureCountUsingReflection() {
+        return (int)
+                Arrays.stream(PackageManager.class.getFields())
+                        .filter(field -> Modifier.isStatic(field.getModifiers()))
+                        .filter(field -> Modifier.isFinal(field.getModifiers()))
+                        .filter(field -> field.getName().startsWith("FEATURE_"))
+                        .count();
+    }
 }