Integrate system feature codegen into SystemConfig
Add initial hooks from SystemConfig to query against system features
that are compiled into the framework via build flags. The behavior
is as follows:
* System features compiled as available will always be exposed
* System features compiled as unavailable will never be exposed
* Runtime parsing of system features won't override compiled features
Currently, we log a warning if there's a conflict between the set of
compiled and runtime system features, but this will likely be elevated
to an exception after additional hardening and development.
The current codegen is a no-op with respect to this behavior, as
RELEASE_USE_SYSTEM_FEATURE_BUILD_FLAGS is flagged as off.
A follow-up change will integrate RoSystemFeature queries into:
* ApplicationPackageManager - To bypass binder calls when possible
* SystemServer - For various hasSystemFeature checks
Bug: 203143243
Test: atest FrameworksServicesTests
Flag: build.RELEASE_USE_SYSTEM_FEATURE_BUILD_FLAGS
Change-Id: I1fcd2f2f86dc5605f33182e88fc98a21b57bf812
diff --git a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
index cba521e..196b5e7 100644
--- a/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
+++ b/tools/systemfeatures/src/com/android/systemfeatures/SystemFeaturesGenerator.kt
@@ -22,8 +22,6 @@
import com.squareup.javapoet.MethodSpec
import com.squareup.javapoet.ParameterizedTypeName
import com.squareup.javapoet.TypeSpec
-import java.util.HashMap
-import java.util.Map
import javax.lang.model.element.Modifier
/*
@@ -52,7 +50,7 @@
* public static boolean hasFeatureAutomotive(Context context);
* public static boolean hasFeatureLeanback(Context context);
* public static Boolean maybeHasFeature(String feature, int version);
- * public static ArrayMap<String, FeatureInfo> getCompileTimeAvailableFeatures();
+ * public static ArrayMap<String, FeatureInfo> getReadOnlySystemEnabledFeatures();
* }
* </pre>
*/
@@ -63,6 +61,7 @@
private val PACKAGEMANAGER_CLASS = ClassName.get("android.content.pm", "PackageManager")
private val CONTEXT_CLASS = ClassName.get("android.content", "Context")
private val FEATUREINFO_CLASS = ClassName.get("android.content.pm", "FeatureInfo")
+ private val ARRAYMAP_CLASS = ClassName.get("android.util", "ArrayMap")
private val ASSUME_TRUE_CLASS =
ClassName.get("com.android.aconfig.annotations", "AssumeTrueForR8")
private val ASSUME_FALSE_CLASS =
@@ -291,19 +290,19 @@
features: Collection<FeatureInfo>,
) {
val methodBuilder =
- MethodSpec.methodBuilder("getCompileTimeAvailableFeatures")
+ MethodSpec.methodBuilder("getReadOnlySystemEnabledFeatures")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addAnnotation(ClassName.get("android.annotation", "NonNull"))
.addJavadoc("Gets features marked as available at compile-time, keyed by name." +
"\n\n@hide")
.returns(ParameterizedTypeName.get(
- ClassName.get(Map::class.java),
+ ARRAYMAP_CLASS,
ClassName.get(String::class.java),
FEATUREINFO_CLASS))
val availableFeatures = features.filter { it.readonly && it.version != null }
- methodBuilder.addStatement("Map<String, FeatureInfo> features = new \$T<>(\$L)",
- HashMap::class.java, availableFeatures.size)
+ methodBuilder.addStatement("\$T<String, FeatureInfo> features = new \$T<>(\$L)",
+ ARRAYMAP_CLASS, ARRAYMAP_CLASS, availableFeatures.size)
if (!availableFeatures.isEmpty()) {
methodBuilder.addStatement("FeatureInfo fi = new FeatureInfo()")
}
diff --git a/tools/systemfeatures/tests/golden/RoFeatures.java.gen b/tools/systemfeatures/tests/golden/RoFeatures.java.gen
index edbfc42..ee97b26 100644
--- a/tools/systemfeatures/tests/golden/RoFeatures.java.gen
+++ b/tools/systemfeatures/tests/golden/RoFeatures.java.gen
@@ -13,10 +13,9 @@
import android.content.Context;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager;
+import android.util.ArrayMap;
import com.android.aconfig.annotations.AssumeFalseForR8;
import com.android.aconfig.annotations.AssumeTrueForR8;
-import java.util.HashMap;
-import java.util.Map;
/**
* @hide
@@ -94,8 +93,8 @@
* @hide
*/
@NonNull
- public static Map<String, FeatureInfo> getCompileTimeAvailableFeatures() {
- Map<String, FeatureInfo> features = new HashMap<>(2);
+ public static ArrayMap<String, FeatureInfo> getReadOnlySystemEnabledFeatures() {
+ ArrayMap<String, FeatureInfo> features = new ArrayMap<>(2);
FeatureInfo fi = new FeatureInfo();
fi.name = PackageManager.FEATURE_WATCH;
fi.version = 1;
diff --git a/tools/systemfeatures/tests/golden/RoNoFeatures.java.gen b/tools/systemfeatures/tests/golden/RoNoFeatures.java.gen
index bf7a006..40c7db7 100644
--- a/tools/systemfeatures/tests/golden/RoNoFeatures.java.gen
+++ b/tools/systemfeatures/tests/golden/RoNoFeatures.java.gen
@@ -9,8 +9,7 @@
import android.content.Context;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager;
-import java.util.HashMap;
-import java.util.Map;
+import android.util.ArrayMap;
/**
* @hide
@@ -43,8 +42,8 @@
* @hide
*/
@NonNull
- public static Map<String, FeatureInfo> getCompileTimeAvailableFeatures() {
- Map<String, FeatureInfo> features = new HashMap<>(0);
+ public static ArrayMap<String, FeatureInfo> getReadOnlySystemEnabledFeatures() {
+ ArrayMap<String, FeatureInfo> features = new ArrayMap<>(0);
return features;
}
}
diff --git a/tools/systemfeatures/tests/golden/RwFeatures.java.gen b/tools/systemfeatures/tests/golden/RwFeatures.java.gen
index b20b228..7bf8961 100644
--- a/tools/systemfeatures/tests/golden/RwFeatures.java.gen
+++ b/tools/systemfeatures/tests/golden/RwFeatures.java.gen
@@ -12,8 +12,7 @@
import android.content.Context;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager;
-import java.util.HashMap;
-import java.util.Map;
+import android.util.ArrayMap;
/**
* @hide
@@ -73,8 +72,8 @@
* @hide
*/
@NonNull
- public static Map<String, FeatureInfo> getCompileTimeAvailableFeatures() {
- Map<String, FeatureInfo> features = new HashMap<>(0);
+ public static ArrayMap<String, FeatureInfo> getReadOnlySystemEnabledFeatures() {
+ ArrayMap<String, FeatureInfo> features = new ArrayMap<>(0);
return features;
}
}
diff --git a/tools/systemfeatures/tests/golden/RwNoFeatures.java.gen b/tools/systemfeatures/tests/golden/RwNoFeatures.java.gen
index d91f5b6..eb7ec63 100644
--- a/tools/systemfeatures/tests/golden/RwNoFeatures.java.gen
+++ b/tools/systemfeatures/tests/golden/RwNoFeatures.java.gen
@@ -7,8 +7,7 @@
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.FeatureInfo;
-import java.util.HashMap;
-import java.util.Map;
+import android.util.ArrayMap;
/**
* @hide
@@ -32,8 +31,8 @@
* @hide
*/
@NonNull
- public static Map<String, FeatureInfo> getCompileTimeAvailableFeatures() {
- Map<String, FeatureInfo> features = new HashMap<>(0);
+ public static ArrayMap<String, FeatureInfo> getReadOnlySystemEnabledFeatures() {
+ ArrayMap<String, FeatureInfo> features = new ArrayMap<>(0);
return features;
}
}
diff --git a/tools/systemfeatures/tests/src/ArrayMap.java b/tools/systemfeatures/tests/src/ArrayMap.java
new file mode 100644
index 0000000..a5ed9b0
--- /dev/null
+++ b/tools/systemfeatures/tests/src/ArrayMap.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import java.util.HashMap;
+
+/** Stub for testing. */
+public final class ArrayMap<K, V> extends HashMap<K, V> {
+ public ArrayMap(int capacity) {
+ super(capacity);
+ }
+}
diff --git a/tools/systemfeatures/tests/src/SystemFeaturesGeneratorTest.java b/tools/systemfeatures/tests/src/SystemFeaturesGeneratorTest.java
index 39f8fc4..ed3f5c9 100644
--- a/tools/systemfeatures/tests/src/SystemFeaturesGeneratorTest.java
+++ b/tools/systemfeatures/tests/src/SystemFeaturesGeneratorTest.java
@@ -60,7 +60,7 @@
assertThat(RwNoFeatures.maybeHasFeature(PackageManager.FEATURE_VULKAN, 0)).isNull();
assertThat(RwNoFeatures.maybeHasFeature(PackageManager.FEATURE_AUTO, 0)).isNull();
assertThat(RwNoFeatures.maybeHasFeature("com.arbitrary.feature", 0)).isNull();
- assertThat(RwNoFeatures.getCompileTimeAvailableFeatures()).isEmpty();
+ assertThat(RwNoFeatures.getReadOnlySystemEnabledFeatures()).isEmpty();
}
@Test
@@ -72,7 +72,7 @@
assertThat(RoNoFeatures.maybeHasFeature(PackageManager.FEATURE_VULKAN, 0)).isNull();
assertThat(RoNoFeatures.maybeHasFeature(PackageManager.FEATURE_AUTO, 0)).isNull();
assertThat(RoNoFeatures.maybeHasFeature("com.arbitrary.feature", 0)).isNull();
- assertThat(RoNoFeatures.getCompileTimeAvailableFeatures()).isEmpty();
+ assertThat(RoNoFeatures.getReadOnlySystemEnabledFeatures()).isEmpty();
// Also ensure we fall back to the PackageManager for feature APIs without an accompanying
// versioned feature definition.
@@ -106,7 +106,7 @@
assertThat(RwFeatures.maybeHasFeature(PackageManager.FEATURE_VULKAN, 0)).isNull();
assertThat(RwFeatures.maybeHasFeature(PackageManager.FEATURE_AUTO, 0)).isNull();
assertThat(RwFeatures.maybeHasFeature("com.arbitrary.feature", 0)).isNull();
- assertThat(RwFeatures.getCompileTimeAvailableFeatures()).isEmpty();
+ assertThat(RwFeatures.getReadOnlySystemEnabledFeatures()).isEmpty();
}
@Test
@@ -163,7 +163,7 @@
assertThat(RoFeatures.maybeHasFeature("com.arbitrary.feature", 100)).isNull();
assertThat(RoFeatures.maybeHasFeature("", 0)).isNull();
- Map<String, FeatureInfo> compiledFeatures = RoFeatures.getCompileTimeAvailableFeatures();
+ Map<String, FeatureInfo> compiledFeatures = RoFeatures.getReadOnlySystemEnabledFeatures();
assertThat(compiledFeatures.keySet())
.containsExactly(PackageManager.FEATURE_WATCH, PackageManager.FEATURE_WIFI);
assertThat(compiledFeatures.get(PackageManager.FEATURE_WATCH).version).isEqualTo(1);