diff options
-rw-r--r-- | core/Makefile | 1 | ||||
-rw-r--r-- | core/dex_preopt.mk | 25 | ||||
-rw-r--r-- | core/tasks/meta-lic.mk | 17 | ||||
-rw-r--r-- | target/product/handheld_system.mk | 3 | ||||
-rw-r--r-- | teams/Android.bp | 7 | ||||
-rw-r--r-- | tools/aconfig/aconfig/src/codegen/java.rs | 330 | ||||
-rw-r--r-- | tools/aconfig/aconfig/templates/CustomFeatureFlags.java.template | 70 | ||||
-rw-r--r-- | tools/aconfig/aconfig/templates/FakeFeatureFlagsImpl.java.template | 73 | ||||
-rw-r--r-- | tools/aconfig/aconfig_storage_read_api/Android.bp | 8 | ||||
-rw-r--r-- | tools/aconfig/aconfig_storage_read_api/libaconfig_storage_read_api_cc.map | 11 | ||||
-rw-r--r-- | tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt | 57 | ||||
-rw-r--r-- | tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt | 47 |
12 files changed, 429 insertions, 220 deletions
diff --git a/core/Makefile b/core/Makefile index e6a5bc0d4f..e563873798 100644 --- a/core/Makefile +++ b/core/Makefile @@ -6919,6 +6919,7 @@ PATH=$(INTERNAL_USERIMAGES_BINARY_PATHS):$(dir $(ZIP2ZIP)):$$PATH \ --verbose \ --path $(HOST_OUT) \ $(if $(OEM_OTA_CONFIG), --oem_settings $(OEM_OTA_CONFIG)) \ + $(if $(BOOT_VAR_OTA_CONFIG), --boot_variable_file $(BOOT_VAR_OTA_CONFIG)) \ $(2) \ $(patsubst %.zip,%,$(BUILT_TARGET_FILES_PACKAGE)) $(1) endef diff --git a/core/dex_preopt.mk b/core/dex_preopt.mk index 08311ca481..26b8b17a49 100644 --- a/core/dex_preopt.mk +++ b/core/dex_preopt.mk @@ -123,22 +123,28 @@ $(boot_zip): $(bootclasspath_jars) $(system_server_jars) $(SOONG_ZIP) $(MERGE_ZI $(call dist-for-goals, droidcore, $(boot_zip)) -ifneq (,$(filter true,$(ART_MODULE_BUILD_FROM_SOURCE) $(MODULE_BUILD_FROM_SOURCE))) # Build the system_server.zip which contains the Apex system server jars and standalone system server jars +system_server_dex2oat_dir := $(SOONG_OUT_DIR)/system_server_dexjars system_server_zip := $(PRODUCT_OUT)/system_server.zip +# non_updatable_system_server_jars contains jars in /system and /system_ext that are not part of an apex. +non_updatable_system_server_jars := \ + $(foreach m,$(PRODUCT_SYSTEM_SERVER_JARS),\ + $(system_server_dex2oat_dir)/$(call word-colon,2,$(m)).jar) + apex_system_server_jars := \ $(foreach m,$(PRODUCT_APEX_SYSTEM_SERVER_JARS),\ - $(PRODUCT_OUT)/apex/$(call word-colon,1,$(m))/javalib/$(call word-colon,2,$(m)).jar) + $(system_server_dex2oat_dir)/$(call word-colon,2,$(m)).jar) apex_standalone_system_server_jars := \ $(foreach m,$(PRODUCT_APEX_STANDALONE_SYSTEM_SERVER_JARS),\ - $(PRODUCT_OUT)/apex/$(call word-colon,1,$(m))/javalib/$(call word-colon,2,$(m)).jar) + $(system_server_dex2oat_dir)/$(call word-colon,2,$(m)).jar) standalone_system_server_jars := \ $(foreach m,$(PRODUCT_STANDALONE_SYSTEM_SERVER_JARS),\ - $(PRODUCT_OUT)/apex/$(call word-colon,1,$(m))/javalib/$(call word-colon,2,$(m)).jar) + $(system_server_dex2oat_dir)/$(call word-colon,2,$(m)).jar) -$(system_server_zip): PRIVATE_SYSTEM_SERVER_JARS := $(system_server_jars) +$(system_server_zip): PRIVATE_SYSTEM_SERVER_DEX2OAT_DIR := $(system_server_dex2oat_dir) +$(system_server_zip): PRIVATE_SYSTEM_SERVER_JARS := $(non_updatable_system_server_jars) $(system_server_zip): PRIVATE_APEX_SYSTEM_SERVER_JARS := $(apex_system_server_jars) $(system_server_zip): PRIVATE_APEX_STANDALONE_SYSTEM_SERVER_JARS := $(apex_standalone_system_server_jars) $(system_server_zip): PRIVATE_STANDALONE_SYSTEM_SERVER_JARS := $(standalone_system_server_jars) @@ -146,14 +152,13 @@ $(system_server_zip): $(system_server_jars) $(apex_system_server_jars) $(apex_st @echo "Create system server package: $@" rm -f $@ $(SOONG_ZIP) -o $@ \ - -C $(PRODUCT_OUT) $(addprefix -f ,$(PRIVATE_SYSTEM_SERVER_JARS)) \ - -C $(PRODUCT_OUT) $(addprefix -f ,$(PRIVATE_APEX_SYSTEM_SERVER_JARS)) \ - -C $(PRODUCT_OUT) $(addprefix -f ,$(PRIVATE_APEX_STANDALONE_SYSTEM_SERVER_JARS)) \ - -C $(PRODUCT_OUT) $(addprefix -f ,$(PRIVATE_STANDALONE_SYSTEM_SERVER_JARS)) + -C $(PRIVATE_SYSTEM_SERVER_DEX2OAT_DIR) $(addprefix -f ,$(PRIVATE_SYSTEM_SERVER_JARS)) \ + -C $(PRIVATE_SYSTEM_SERVER_DEX2OAT_DIR) $(addprefix -f ,$(PRIVATE_APEX_SYSTEM_SERVER_JARS)) \ + -C $(PRIVATE_SYSTEM_SERVER_DEX2OAT_DIR) $(addprefix -f ,$(PRIVATE_APEX_STANDALONE_SYSTEM_SERVER_JARS)) \ + -C $(PRIVATE_SYSTEM_SERVER_DEX2OAT_DIR) $(addprefix -f ,$(PRIVATE_STANDALONE_SYSTEM_SERVER_JARS)) $(call dist-for-goals, droidcore, $(system_server_zip)) -endif #ART_MODULE_BUILD_FROM_SOURCE || MODULE_BUILD_FROM_SOURCE endif #PRODUCT_USES_DEFAULT_ART_CONFIG endif #WITH_DEXPREOPT_ART_BOOT_IMG_ONLY endif #WITH_DEXPREOPT diff --git a/core/tasks/meta-lic.mk b/core/tasks/meta-lic.mk index 99ecd83fa1..1094726b6d 100644 --- a/core/tasks/meta-lic.mk +++ b/core/tasks/meta-lic.mk @@ -49,6 +49,23 @@ $(eval $(call declare-copy-files-license-metadata,device/google/coral,display_19 $(eval $(call declare-1p-copy-files,device/google/coral,audio_policy_configuration.xml)) $(eval $(call declare-1p-copy-files,device/google/coral,display_19260504575090817.xml)) +# Moved here from device/google/gs101/Android.mk +$(eval $(call declare-copy-files-license-metadata,device/google/gs101,default-permissions.xml,SPDX-license-identifier-Apache-2.0,notice,build/soong/licenses/LICENSE,)) +$(eval $(call declare-copy-files-license-metadata,device/google/gs101,libnfc-nci.conf,SPDX-license-identifier-Apache-2.0,notice,build/soong/licenses/LICENSE,)) +$(eval $(call declare-copy-files-license-metadata,device/google/gs101,fstab.postinstall,SPDX-license-identifier-Apache-2.0,notice,build/soong/licenses/LICENSE,)) +$(eval $(call declare-copy-files-license-metadata,device/google/gs101,ueventd.rc,SPDX-license-identifier-Apache-2.0,notice,build/soong/licenses/LICENSE,)) +$(eval $(call declare-copy-files-license-metadata,device/google/gs101,wpa_supplicant.conf,SPDX-license-identifier-Apache-2.0,notice,build/soong/licenses/LICENSE,)) +$(eval $(call declare-copy-files-license-metadata,device/google/gs101,hals.conf,SPDX-license-identifier-Apache-2.0,notice,build/soong/licenses/LICENSE,)) +$(eval $(call declare-copy-files-license-metadata,device/google/gs101,media_profiles_V1_0.xml,SPDX-license-identifier-Apache-2.0,notice,build/soong/licenses/LICENSE,)) +$(eval $(call declare-copy-files-license-metadata,device/google/gs101,media_codecs_performance.xml,SPDX-license-identifier-Apache-2.0,notice,build/soong/licenses/LICENSE,)) +$(eval $(call declare-copy-files-license-metadata,device/google/gs101,device_state_configuration.xml,SPDX-license-identifier-Apache-2.0,notice,build/soong/licenses/LICENSE,)) +$(eval $(call declare-copy-files-license-metadata,device/google/gs101,task_profiles.json,SPDX-license-identifier-Apache-2.0,notice,build/soong/licenses/LICENSE,)) +$(eval $(call declare-copy-files-license-metadata,device/google/gs101,p2p_supplicant_overlay.conf,SPDX-license-identifier-Apache-2.0,notice,build/soong/licenses/LICENSE,)) +$(eval $(call declare-copy-files-license-metadata,device/google/gs101,wpa_supplicant.conf,SPDX-license-identifier-Apache-2.0,notice,build/soong/licenses/LICENSE,)) +$(eval $(call declare-copy-files-license-metadata,device/google/gs101,wpa_supplicant_overlay.conf,SPDX-license-identifier-Apache-2.0,notice,build/soong/licenses/LICENSE,)) + +$(eval $(call declare-1p-copy-files,device/google/gs101,audio_policy_configuration.xml)) + # Moved here from device/sample/Android.mk $(eval $(call declare-1p-copy-files,device/sample,)) diff --git a/target/product/handheld_system.mk b/target/product/handheld_system.mk index bf9aa418f9..3c401f399b 100644 --- a/target/product/handheld_system.mk +++ b/target/product/handheld_system.mk @@ -82,8 +82,9 @@ PRODUCT_SYSTEM_SERVER_APPS += \ KeyChain \ Telecom \ +PRODUCT_PACKAGES += framework-audio_effects.xml + PRODUCT_COPY_FILES += \ - frameworks/av/media/libeffects/data/audio_effects.xml:system/etc/audio_effects.xml \ frameworks/native/data/etc/android.software.window_magnification.xml:$(TARGET_COPY_OUT_SYSTEM)/etc/permissions/android.software.window_magnification.xml \ PRODUCT_VENDOR_PROPERTIES += \ diff --git a/teams/Android.bp b/teams/Android.bp index a02a57392c..78efa61f03 100644 --- a/teams/Android.bp +++ b/teams/Android.bp @@ -4371,3 +4371,10 @@ team { // go/trendy/manage/engineers/5810097836621824 trendy_team_id: "5810097836621824", } + +team { + name: "trendy_team_adte", + + // go/trendy/manage/engineers/5551098528825344 + trendy_team_id: "5551098528825344", +} diff --git a/tools/aconfig/aconfig/src/codegen/java.rs b/tools/aconfig/aconfig/src/codegen/java.rs index 18a4be5094..9abc892908 100644 --- a/tools/aconfig/aconfig/src/codegen/java.rs +++ b/tools/aconfig/aconfig/src/codegen/java.rs @@ -64,20 +64,27 @@ where include_str!("../../templates/FeatureFlags.java.template"), )?; template.add_template( + "CustomFeatureFlags.java", + include_str!("../../templates/CustomFeatureFlags.java.template"), + )?; + template.add_template( "FakeFeatureFlagsImpl.java", include_str!("../../templates/FakeFeatureFlagsImpl.java.template"), )?; let path: PathBuf = package.split('.').collect(); - ["Flags.java", "FeatureFlags.java", "FeatureFlagsImpl.java", "FakeFeatureFlagsImpl.java"] - .iter() - .map(|file| { - Ok(OutputFile { - contents: template.render(file, &context)?.into(), - path: path.join(file), - }) - }) - .collect::<Result<Vec<OutputFile>>>() + [ + "Flags.java", + "FeatureFlags.java", + "FeatureFlagsImpl.java", + "CustomFeatureFlags.java", + "FakeFeatureFlagsImpl.java", + ] + .iter() + .map(|file| { + Ok(OutputFile { contents: template.render(file, &context)?.into(), path: path.join(file) }) + }) + .collect::<Result<Vec<OutputFile>>>() } fn gen_flags_by_namespace(flags: &[FlagElement]) -> Vec<NamespaceFlags> { @@ -292,76 +299,82 @@ mod tests { } "#; - const EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT: &str = r#" + const EXPECTED_CUSTOMFEATUREFLAGS_CONTENT: &str = r#" package com.android.aconfig.test; + // TODO(b/303773055): Remove the annotation after access issue is resolved. import android.compat.annotation.UnsupportedAppUsage; import java.util.Arrays; - import java.util.HashMap; import java.util.HashSet; - import java.util.Map; + import java.util.List; import java.util.Set; + import java.util.function.BiPredicate; + import java.util.function.Predicate; + /** @hide */ - public class FakeFeatureFlagsImpl implements FeatureFlags { - public FakeFeatureFlagsImpl() { - resetAll(); + public class CustomFeatureFlags implements FeatureFlags { + + private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl; + + public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) { + mGetValueImpl = getValueImpl; } + @Override @UnsupportedAppUsage public boolean disabledRo() { - return getValue(Flags.FLAG_DISABLED_RO); + return getValue(Flags.FLAG_DISABLED_RO, + FeatureFlags::disabledRo); } @Override @UnsupportedAppUsage public boolean disabledRw() { - return getValue(Flags.FLAG_DISABLED_RW); + return getValue(Flags.FLAG_DISABLED_RW, + FeatureFlags::disabledRw); } @Override @UnsupportedAppUsage public boolean disabledRwExported() { - return getValue(Flags.FLAG_DISABLED_RW_EXPORTED); + return getValue(Flags.FLAG_DISABLED_RW_EXPORTED, + FeatureFlags::disabledRwExported); } @Override @UnsupportedAppUsage public boolean disabledRwInOtherNamespace() { - return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE); + return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, + FeatureFlags::disabledRwInOtherNamespace); } @Override @UnsupportedAppUsage public boolean enabledFixedRo() { - return getValue(Flags.FLAG_ENABLED_FIXED_RO); + return getValue(Flags.FLAG_ENABLED_FIXED_RO, + FeatureFlags::enabledFixedRo); } @Override @UnsupportedAppUsage public boolean enabledFixedRoExported() { - return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED); + return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, + FeatureFlags::enabledFixedRoExported); } @Override @UnsupportedAppUsage public boolean enabledRo() { - return getValue(Flags.FLAG_ENABLED_RO); + return getValue(Flags.FLAG_ENABLED_RO, + FeatureFlags::enabledRo); } @Override @UnsupportedAppUsage public boolean enabledRoExported() { - return getValue(Flags.FLAG_ENABLED_RO_EXPORTED); + return getValue(Flags.FLAG_ENABLED_RO_EXPORTED, + FeatureFlags::enabledRoExported); } @Override @UnsupportedAppUsage public boolean enabledRw() { - return getValue(Flags.FLAG_ENABLED_RW); - } - public void setFlag(String flagName, boolean value) { - if (!this.mFlagMap.containsKey(flagName)) { - throw new IllegalArgumentException("no such flag " + flagName); - } - this.mFlagMap.put(flagName, value); - } - public void resetAll() { - for (Map.Entry entry : mFlagMap.entrySet()) { - entry.setValue(null); - } + return getValue(Flags.FLAG_ENABLED_RW, + FeatureFlags::enabledRw); } + public boolean isFlagReadOnlyOptimized(String flagName) { if (mReadOnlyFlagsSet.contains(flagName) && isOptimizationEnabled()) { @@ -369,30 +382,30 @@ mod tests { } return false; } + @com.android.aconfig.annotations.AssumeTrueForR8 private boolean isOptimizationEnabled() { return false; } - private boolean getValue(String flagName) { - Boolean value = this.mFlagMap.get(flagName); - if (value == null) { - throw new IllegalArgumentException(flagName + " is not set"); - } - return value; + + protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) { + return mGetValueImpl.test(flagName, getter); } - private Map<String, Boolean> mFlagMap = new HashMap<>( - Map.ofEntries( - Map.entry(Flags.FLAG_DISABLED_RO, false), - Map.entry(Flags.FLAG_DISABLED_RW, false), - Map.entry(Flags.FLAG_DISABLED_RW_EXPORTED, false), - Map.entry(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, false), - Map.entry(Flags.FLAG_ENABLED_FIXED_RO, false), - Map.entry(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, false), - Map.entry(Flags.FLAG_ENABLED_RO, false), - Map.entry(Flags.FLAG_ENABLED_RO_EXPORTED, false), - Map.entry(Flags.FLAG_ENABLED_RW, false) - ) - ); + + public List<String> getFlagNames() { + return Arrays.asList( + Flags.FLAG_DISABLED_RO, + Flags.FLAG_DISABLED_RW, + Flags.FLAG_DISABLED_RW_EXPORTED, + Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, + Flags.FLAG_ENABLED_FIXED_RO, + Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, + Flags.FLAG_ENABLED_RO, + Flags.FLAG_ENABLED_RO_EXPORTED, + Flags.FLAG_ENABLED_RW + ); + } + private Set<String> mReadOnlyFlagsSet = new HashSet<>( Arrays.asList( Flags.FLAG_DISABLED_RO, @@ -406,6 +419,49 @@ mod tests { } "#; + const EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT: &str = r#" + package com.android.aconfig.test; + + import java.util.HashMap; + import java.util.Map; + import java.util.function.Predicate; + + /** @hide */ + public class FakeFeatureFlagsImpl extends CustomFeatureFlags { + private Map<String, Boolean> mFlagMap = new HashMap<>(); + + public FakeFeatureFlagsImpl() { + super(null); + // Initialize the map with null values + for (String flagName : getFlagNames()) { + mFlagMap.put(flagName, null); + } + } + + @Override + protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) { + Boolean value = this.mFlagMap.get(flagName); + if (value == null) { + throw new IllegalArgumentException(flagName + " is not set"); + } + return value; + } + + public void setFlag(String flagName, boolean value) { + if (!this.mFlagMap.containsKey(flagName)) { + throw new IllegalArgumentException("no such flag " + flagName); + } + this.mFlagMap.put(flagName, value); + } + + public void resetAll() { + for (Map.Entry entry : mFlagMap.entrySet()) { + entry.setValue(null); + } + } + } + "#; + #[test] fn test_generate_java_code_production() { let parsed_flags = crate::test::parse_test_flags(); @@ -549,6 +605,10 @@ mod tests { ("com/android/aconfig/test/FeatureFlagsImpl.java", expect_featureflagsimpl_content), ("com/android/aconfig/test/FeatureFlags.java", EXPECTED_FEATUREFLAGS_COMMON_CONTENT), ( + "com/android/aconfig/test/CustomFeatureFlags.java", + EXPECTED_CUSTOMFEATUREFLAGS_CONTENT, + ), + ( "com/android/aconfig/test/FakeFeatureFlagsImpl.java", EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT, ), @@ -671,55 +731,53 @@ mod tests { } }"#; - let expect_fake_feature_flags_impl_content = r#" + let expect_custom_feature_flags_content = r#" package com.android.aconfig.test; + import java.util.Arrays; - import java.util.HashMap; import java.util.HashSet; - import java.util.Map; + import java.util.List; import java.util.Set; + import java.util.function.BiPredicate; + import java.util.function.Predicate; + /** @hide */ - public class FakeFeatureFlagsImpl implements FeatureFlags { - public FakeFeatureFlagsImpl() { - resetAll(); + public class CustomFeatureFlags implements FeatureFlags { + + private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl; + + public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) { + mGetValueImpl = getValueImpl; } + @Override public boolean disabledRwExported() { - return getValue(Flags.FLAG_DISABLED_RW_EXPORTED); + return getValue(Flags.FLAG_DISABLED_RW_EXPORTED, + FeatureFlags::disabledRwExported); } @Override public boolean enabledFixedRoExported() { - return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED); + return getValue(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, + FeatureFlags::enabledFixedRoExported); } @Override public boolean enabledRoExported() { - return getValue(Flags.FLAG_ENABLED_RO_EXPORTED); - } - public void setFlag(String flagName, boolean value) { - if (!this.mFlagMap.containsKey(flagName)) { - throw new IllegalArgumentException("no such flag " + flagName); - } - this.mFlagMap.put(flagName, value); + return getValue(Flags.FLAG_ENABLED_RO_EXPORTED, + FeatureFlags::enabledRoExported); } - public void resetAll() { - for (Map.Entry entry : mFlagMap.entrySet()) { - entry.setValue(null); - } + + protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) { + return mGetValueImpl.test(flagName, getter); } - private boolean getValue(String flagName) { - Boolean value = this.mFlagMap.get(flagName); - if (value == null) { - throw new IllegalArgumentException(flagName + " is not set"); - } - return value; + + public List<String> getFlagNames() { + return Arrays.asList( + Flags.FLAG_DISABLED_RW_EXPORTED, + Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, + Flags.FLAG_ENABLED_RO_EXPORTED + ); } - private Map<String, Boolean> mFlagMap = new HashMap<>( - Map.ofEntries( - Map.entry(Flags.FLAG_DISABLED_RW_EXPORTED, false), - Map.entry(Flags.FLAG_ENABLED_FIXED_RO_EXPORTED, false), - Map.entry(Flags.FLAG_ENABLED_RO_EXPORTED, false) - ) - ); + private Set<String> mReadOnlyFlagsSet = new HashSet<>( Arrays.asList( "" @@ -733,8 +791,12 @@ mod tests { ("com/android/aconfig/test/FeatureFlags.java", expect_feature_flags_content), ("com/android/aconfig/test/FeatureFlagsImpl.java", expect_feature_flags_impl_content), ( + "com/android/aconfig/test/CustomFeatureFlags.java", + expect_custom_feature_flags_content, + ), + ( "com/android/aconfig/test/FakeFeatureFlagsImpl.java", - expect_fake_feature_flags_impl_content, + EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT, ), ]); @@ -854,6 +916,10 @@ mod tests { ("com/android/aconfig/test/FeatureFlags.java", EXPECTED_FEATUREFLAGS_COMMON_CONTENT), ("com/android/aconfig/test/FeatureFlagsImpl.java", expect_featureflagsimpl_content), ( + "com/android/aconfig/test/CustomFeatureFlags.java", + EXPECTED_CUSTOMFEATUREFLAGS_CONTENT, + ), + ( "com/android/aconfig/test/FakeFeatureFlagsImpl.java", EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT, ), @@ -1020,61 +1086,64 @@ mod tests { private static FeatureFlags FEATURE_FLAGS = new FeatureFlagsImpl(); }"#; - let expect_fakefeatureflags_content = r#" + let expect_customfeatureflags_content = r#" package com.android.aconfig.test; + // TODO(b/303773055): Remove the annotation after access issue is resolved. import android.compat.annotation.UnsupportedAppUsage; import java.util.Arrays; - import java.util.HashMap; import java.util.HashSet; - import java.util.Map; + import java.util.List; import java.util.Set; + import java.util.function.BiPredicate; + import java.util.function.Predicate; + /** @hide */ - public class FakeFeatureFlagsImpl implements FeatureFlags { - public FakeFeatureFlagsImpl() { - resetAll(); + public class CustomFeatureFlags implements FeatureFlags { + + private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl; + + public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) { + mGetValueImpl = getValueImpl; } + @Override @UnsupportedAppUsage public boolean disabledRo() { - return getValue(Flags.FLAG_DISABLED_RO); + return getValue(Flags.FLAG_DISABLED_RO, + FeatureFlags::disabledRo); } @Override @UnsupportedAppUsage public boolean disabledRw() { - return getValue(Flags.FLAG_DISABLED_RW); + return getValue(Flags.FLAG_DISABLED_RW, + FeatureFlags::disabledRw); } @Override @UnsupportedAppUsage public boolean disabledRwInOtherNamespace() { - return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE); + return getValue(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, + FeatureFlags::disabledRwInOtherNamespace); } @Override @UnsupportedAppUsage public boolean enabledFixedRo() { - return getValue(Flags.FLAG_ENABLED_FIXED_RO); + return getValue(Flags.FLAG_ENABLED_FIXED_RO, + FeatureFlags::enabledFixedRo); } @Override @UnsupportedAppUsage public boolean enabledRo() { - return getValue(Flags.FLAG_ENABLED_RO); + return getValue(Flags.FLAG_ENABLED_RO, + FeatureFlags::enabledRo); } @Override @UnsupportedAppUsage public boolean enabledRw() { - return getValue(Flags.FLAG_ENABLED_RW); - } - public void setFlag(String flagName, boolean value) { - if (!this.mFlagMap.containsKey(flagName)) { - throw new IllegalArgumentException("no such flag " + flagName); - } - this.mFlagMap.put(flagName, value); - } - public void resetAll() { - for (Map.Entry entry : mFlagMap.entrySet()) { - entry.setValue(null); - } + return getValue(Flags.FLAG_ENABLED_RW, + FeatureFlags::enabledRw); } + public boolean isFlagReadOnlyOptimized(String flagName) { if (mReadOnlyFlagsSet.contains(flagName) && isOptimizationEnabled()) { @@ -1082,27 +1151,27 @@ mod tests { } return false; } + @com.android.aconfig.annotations.AssumeTrueForR8 private boolean isOptimizationEnabled() { return false; } - private boolean getValue(String flagName) { - Boolean value = this.mFlagMap.get(flagName); - if (value == null) { - throw new IllegalArgumentException(flagName + " is not set"); - } - return value; - } - private Map<String, Boolean> mFlagMap = new HashMap<>( - Map.ofEntries( - Map.entry(Flags.FLAG_DISABLED_RO, false), - Map.entry(Flags.FLAG_DISABLED_RW, false), - Map.entry(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, false), - Map.entry(Flags.FLAG_ENABLED_FIXED_RO, false), - Map.entry(Flags.FLAG_ENABLED_RO, false), - Map.entry(Flags.FLAG_ENABLED_RW, false) - ) - ); + + protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) { + return mGetValueImpl.test(flagName, getter); + } + + public List<String> getFlagNames() { + return Arrays.asList( + Flags.FLAG_DISABLED_RO, + Flags.FLAG_DISABLED_RW, + Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, + Flags.FLAG_ENABLED_FIXED_RO, + Flags.FLAG_ENABLED_RO, + Flags.FLAG_ENABLED_RW + ); + } + private Set<String> mReadOnlyFlagsSet = new HashSet<>( Arrays.asList( Flags.FLAG_DISABLED_RO, @@ -1116,11 +1185,16 @@ mod tests { ); } "#; + let mut file_set = HashMap::from([ ("com/android/aconfig/test/Flags.java", expect_flags_content), ("com/android/aconfig/test/FeatureFlagsImpl.java", expect_featureflagsimpl_content), ("com/android/aconfig/test/FeatureFlags.java", expect_featureflags_content), - ("com/android/aconfig/test/FakeFeatureFlagsImpl.java", expect_fakefeatureflags_content), + ("com/android/aconfig/test/CustomFeatureFlags.java", expect_customfeatureflags_content), + ( + "com/android/aconfig/test/FakeFeatureFlagsImpl.java", + EXPECTED_FAKEFEATUREFLAGSIMPL_CONTENT, + ), ]); for file in generated_files { diff --git a/tools/aconfig/aconfig/templates/CustomFeatureFlags.java.template b/tools/aconfig/aconfig/templates/CustomFeatureFlags.java.template new file mode 100644 index 0000000000..b82b9cb827 --- /dev/null +++ b/tools/aconfig/aconfig/templates/CustomFeatureFlags.java.template @@ -0,0 +1,70 @@ +package {package_name}; + +{{ if not library_exported- }} +// TODO(b/303773055): Remove the annotation after access issue is resolved. +import android.compat.annotation.UnsupportedAppUsage; +{{ -endif }} +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.BiPredicate; +import java.util.function.Predicate; + +/** @hide */ +public class CustomFeatureFlags implements FeatureFlags \{ + + private BiPredicate<String, Predicate<FeatureFlags>> mGetValueImpl; + + public CustomFeatureFlags(BiPredicate<String, Predicate<FeatureFlags>> getValueImpl) \{ + mGetValueImpl = getValueImpl; + } + +{{ -for item in flag_elements}} + @Override +{{ if not library_exported }} @UnsupportedAppUsage{{ -endif }} + public boolean {item.method_name}() \{ + return getValue(Flags.FLAG_{item.flag_name_constant_suffix}, + FeatureFlags::{item.method_name}); + } +{{ endfor }} + +{{ -if not library_exported }} + public boolean isFlagReadOnlyOptimized(String flagName) \{ + if (mReadOnlyFlagsSet.contains(flagName) && + isOptimizationEnabled()) \{ + return true; + } + return false; + } + + @com.android.aconfig.annotations.AssumeTrueForR8 + private boolean isOptimizationEnabled() \{ + return false; + } +{{ -endif }} + + protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) \{ + return mGetValueImpl.test(flagName, getter); + } + + public List<String> getFlagNames() \{ + return Arrays.asList( + {{ -for item in flag_elements }} + Flags.FLAG_{item.flag_name_constant_suffix} + {{ -if not @last }},{{ endif }} + {{ -endfor }} + ); + } + + private Set<String> mReadOnlyFlagsSet = new HashSet<>( + Arrays.asList( + {{ -for item in flag_elements }} + {{ -if not item.is_read_write }} + Flags.FLAG_{item.flag_name_constant_suffix}, + {{ -endif }} + {{ -endfor }} + ""{# The empty string here is to resolve the ending comma #} + ) + ); +} diff --git a/tools/aconfig/aconfig/templates/FakeFeatureFlagsImpl.java.template b/tools/aconfig/aconfig/templates/FakeFeatureFlagsImpl.java.template index 177e711e77..c20d3c5061 100644 --- a/tools/aconfig/aconfig/templates/FakeFeatureFlagsImpl.java.template +++ b/tools/aconfig/aconfig/templates/FakeFeatureFlagsImpl.java.template @@ -1,27 +1,30 @@ package {package_name}; -{{ if not library_exported- }} -// TODO(b/303773055): Remove the annotation after access issue is resolved. -import android.compat.annotation.UnsupportedAppUsage; -{{ -endif }} -import java.util.Arrays; + import java.util.HashMap; -import java.util.HashSet; import java.util.Map; -import java.util.Set; +import java.util.function.Predicate; /** @hide */ -public class FakeFeatureFlagsImpl implements FeatureFlags \{ +public class FakeFeatureFlagsImpl extends CustomFeatureFlags \{ + private Map<String, Boolean> mFlagMap = new HashMap<>(); + public FakeFeatureFlagsImpl() \{ - resetAll(); + super(null); + // Initialize the map with null values + for (String flagName : getFlagNames()) \{ + mFlagMap.put(flagName, null); + } } -{{ for item in flag_elements}} @Override -{{ if not library_exported }} @UnsupportedAppUsage{{ -endif }} - public boolean {item.method_name}() \{ - return getValue(Flags.FLAG_{item.flag_name_constant_suffix}); + protected boolean getValue(String flagName, Predicate<FeatureFlags> getter) \{ + Boolean value = this.mFlagMap.get(flagName); + if (value == null) \{ + throw new IllegalArgumentException(flagName + " is not set"); + } + return value; } -{{ endfor}} + public void setFlag(String flagName, boolean value) \{ if (!this.mFlagMap.containsKey(flagName)) \{ throw new IllegalArgumentException("no such flag " + flagName); @@ -34,46 +37,4 @@ public class FakeFeatureFlagsImpl implements FeatureFlags \{ entry.setValue(null); } } -{{ if not library_exported }} - public boolean isFlagReadOnlyOptimized(String flagName) \{ - if (mReadOnlyFlagsSet.contains(flagName) && - isOptimizationEnabled()) \{ - return true; - } - return false; - } - - @com.android.aconfig.annotations.AssumeTrueForR8 - private boolean isOptimizationEnabled() \{ - return false; - } -{{ -endif }} - private boolean getValue(String flagName) \{ - Boolean value = this.mFlagMap.get(flagName); - if (value == null) \{ - throw new IllegalArgumentException(flagName + " is not set"); - } - return value; - } - - - private Map<String, Boolean> mFlagMap = new HashMap<>( - Map.ofEntries( - {{ -for item in flag_elements }} - Map.entry(Flags.FLAG_{item.flag_name_constant_suffix}, false) - {{ -if not @last }},{{ endif }} - {{ -endfor }} - ) - ); - - private Set<String> mReadOnlyFlagsSet = new HashSet<>( - Arrays.asList( - {{ -for item in flag_elements }} - {{ -if not item.is_read_write }} - Flags.FLAG_{item.flag_name_constant_suffix}, - {{ -endif }} - {{ -endfor }} - ""{# The empty string here is to resolve the ending comma #} - ) - ); } diff --git a/tools/aconfig/aconfig_storage_read_api/Android.bp b/tools/aconfig/aconfig_storage_read_api/Android.bp index 946c00bf23..c89107fddd 100644 --- a/tools/aconfig/aconfig_storage_read_api/Android.bp +++ b/tools/aconfig/aconfig_storage_read_api/Android.bp @@ -102,8 +102,10 @@ cc_library { "//apex_available:anyapex", ], min_sdk_version: "29", + target: { + linux: { + version_script: "libaconfig_storage_read_api_cc.map", + }, + }, double_loadable: true, - cflags: [ - "-fvisibility=hidden", - ], } diff --git a/tools/aconfig/aconfig_storage_read_api/libaconfig_storage_read_api_cc.map b/tools/aconfig/aconfig_storage_read_api/libaconfig_storage_read_api_cc.map new file mode 100644 index 0000000000..7d47e0ba0e --- /dev/null +++ b/tools/aconfig/aconfig_storage_read_api/libaconfig_storage_read_api_cc.map @@ -0,0 +1,11 @@ +LIBACONFIG_STORAGE_READ_API_CC { + # Export everything in the aconfig_storage namespace. This includes both the + # public API and library internals. + global: + extern "C++" { + aconfig_storage::*; + }; + # Hide everything else. + local: + *; +}; diff --git a/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt b/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt index 5d87a4c754..62c9cbb832 100644 --- a/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt +++ b/tools/check-flagged-apis/src/com/android/checkflaggedapis/CheckFlaggedApisTest.kt @@ -16,6 +16,8 @@ package com.android.checkflaggedapis import android.aconfig.Aconfig +import android.aconfig.Aconfig.flag_state.DISABLED +import android.aconfig.Aconfig.flag_state.ENABLED import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream import java.io.InputStream @@ -28,10 +30,12 @@ private val API_SIGNATURE = """ // Signature format: 2.0 package android { - public final class Clazz { + @FlaggedApi("android.flag.foo") public final class Clazz { ctor public Clazz(); field @FlaggedApi("android.flag.foo") public static final int FOO = 1; // 0x1 } + @FlaggedApi("android.flag.bar") public static class Clazz.Builder { + } } """ .trim() @@ -44,12 +48,17 @@ private val API_VERSIONS = <method name="<init>()V"/> <field name="FOO"/> </class> + <class name="android/Clazz${"$"}Builder" since="2"> + </class> </api> """ .trim() -private fun generateFlagsProto(fooState: Aconfig.flag_state): InputStream { - val parsed_flag = +private fun generateFlagsProto( + fooState: Aconfig.flag_state, + barState: Aconfig.flag_state +): InputStream { + val fooFlag = Aconfig.parsed_flag .newBuilder() .setPackage("android.flag") @@ -57,9 +66,18 @@ private fun generateFlagsProto(fooState: Aconfig.flag_state): InputStream { .setState(fooState) .setPermission(Aconfig.flag_permission.READ_ONLY) .build() - val parsed_flags = Aconfig.parsed_flags.newBuilder().addParsedFlag(parsed_flag).build() + val barFlag = + Aconfig.parsed_flag + .newBuilder() + .setPackage("android.flag") + .setName("bar") + .setState(barState) + .setPermission(Aconfig.flag_permission.READ_ONLY) + .build() + val flags = + Aconfig.parsed_flags.newBuilder().addParsedFlag(fooFlag).addParsedFlag(barFlag).build() val binaryProto = ByteArrayOutputStream() - parsed_flags.writeTo(binaryProto) + flags.writeTo(binaryProto) return ByteArrayInputStream(binaryProto.toByteArray()) } @@ -67,21 +85,32 @@ private fun generateFlagsProto(fooState: Aconfig.flag_state): InputStream { class CheckFlaggedApisTest { @Test fun testParseApiSignature() { - val expected = setOf(Pair(Symbol("android.Clazz.FOO"), Flag("android.flag.foo"))) + val expected = + setOf( + Pair(Symbol("android.Clazz"), Flag("android.flag.foo")), + Pair(Symbol("android.Clazz.FOO"), Flag("android.flag.foo")), + Pair(Symbol("android.Clazz.Builder"), Flag("android.flag.bar")), + ) val actual = parseApiSignature("in-memory", API_SIGNATURE.byteInputStream()) assertEquals(expected, actual) } @Test fun testParseFlagValues() { - val expected: Map<Flag, Boolean> = mapOf(Flag("android.flag.foo") to true) - val actual = parseFlagValues(generateFlagsProto(Aconfig.flag_state.ENABLED)) + val expected: Map<Flag, Boolean> = + mapOf(Flag("android.flag.foo") to true, Flag("android.flag.bar") to true) + val actual = parseFlagValues(generateFlagsProto(ENABLED, ENABLED)) assertEquals(expected, actual) } @Test fun testParseApiVersions() { - val expected: Set<Symbol> = setOf(Symbol("android.Clazz.FOO")) + val expected: Set<Symbol> = + setOf( + Symbol("android.Clazz"), + Symbol("android.Clazz.FOO"), + Symbol("android.Clazz.Builder"), + ) val actual = parseApiVersions(API_VERSIONS.byteInputStream()) assertEquals(expected, actual) } @@ -92,7 +121,7 @@ class CheckFlaggedApisTest { val actual = findErrors( parseApiSignature("in-memory", API_SIGNATURE.byteInputStream()), - parseFlagValues(generateFlagsProto(Aconfig.flag_state.ENABLED)), + parseFlagValues(generateFlagsProto(ENABLED, ENABLED)), parseApiVersions(API_VERSIONS.byteInputStream())) assertEquals(expected, actual) } @@ -101,11 +130,15 @@ class CheckFlaggedApisTest { fun testFindErrorsDisabledFlaggedApiIsPresent() { val expected = setOf<ApiError>( - DisabledFlaggedApiIsPresentError(Symbol("android.Clazz.FOO"), Flag("android.flag.foo"))) + DisabledFlaggedApiIsPresentError(Symbol("android.Clazz"), Flag("android.flag.foo")), + DisabledFlaggedApiIsPresentError(Symbol("android.Clazz.FOO"), Flag("android.flag.foo")), + DisabledFlaggedApiIsPresentError( + Symbol("android.Clazz.Builder"), Flag("android.flag.bar")), + ) val actual = findErrors( parseApiSignature("in-memory", API_SIGNATURE.byteInputStream()), - parseFlagValues(generateFlagsProto(Aconfig.flag_state.DISABLED)), + parseFlagValues(generateFlagsProto(DISABLED, DISABLED)), parseApiVersions(API_VERSIONS.byteInputStream())) assertEquals(expected, actual) } diff --git a/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt b/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt index 84564ba34c..918a5d9bf3 100644 --- a/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt +++ b/tools/check-flagged-apis/src/com/android/checkflaggedapis/Main.kt @@ -19,7 +19,9 @@ package com.android.checkflaggedapis import android.aconfig.Aconfig import com.android.tools.metalava.model.BaseItemVisitor +import com.android.tools.metalava.model.ClassItem import com.android.tools.metalava.model.FieldItem +import com.android.tools.metalava.model.Item import com.android.tools.metalava.model.text.ApiFile import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.ProgramResult @@ -167,22 +169,31 @@ The tool will exit with a non-zero exit code if any flagged APIs are found to be } internal fun parseApiSignature(path: String, input: InputStream): Set<Pair<Symbol, Flag>> { - // TODO(334870672): add support for classes and metods + // TODO(334870672): add support for metods val output = mutableSetOf<Pair<Symbol, Flag>>() val visitor = object : BaseItemVisitor() { + override fun visitClass(cls: ClassItem) { + getFlagOrNull(cls)?.let { flag -> + val symbol = Symbol.create(cls.baselineElementId()) + output.add(Pair(symbol, flag)) + } + } + override fun visitField(field: FieldItem) { - val flag = - field.modifiers - .findAnnotation("android.annotation.FlaggedApi") - ?.findAttribute("value") - ?.value - ?.value() as? String - if (flag != null) { + getFlagOrNull(field)?.let { flag -> val symbol = Symbol.create(field.baselineElementId()) - output.add(Pair(symbol, Flag(flag))) + output.add(Pair(symbol, flag)) } } + + private fun getFlagOrNull(item: Item): Flag? { + return item.modifiers + .findAnnotation("android.annotation.FlaggedApi") + ?.findAttribute("value") + ?.value + ?.let { Flag(it.value() as String) } + } } val codebase = ApiFile.parseApi(path, input) codebase.accept(visitor) @@ -203,16 +214,32 @@ internal fun parseApiVersions(input: InputStream): Set<Symbol> { val factory = DocumentBuilderFactory.newInstance() val parser = factory.newDocumentBuilder() val document = parser.parse(input) + + val classes = document.getElementsByTagName("class") + // ktfmt doesn't understand the `..<` range syntax; explicitly call .rangeUntil instead + for (i in 0.rangeUntil(classes.getLength())) { + val cls = classes.item(i) + val className = + requireNotNull(cls.getAttribute("name")) { + "Bad XML: <class> element without name attribute" + } + output.add(Symbol.create(className)) + } + val fields = document.getElementsByTagName("field") // ktfmt doesn't understand the `..<` range syntax; explicitly call .rangeUntil instead for (i in 0.rangeUntil(fields.getLength())) { val field = fields.item(i) - val fieldName = field.getAttribute("name") + val fieldName = + requireNotNull(field.getAttribute("name")) { + "Bad XML: <field> element without name attribute" + } val className = requireNotNull(field.getParentNode()) { "Bad XML: top level <field> element" } .getAttribute("name") output.add(Symbol.create("$className.$fieldName")) } + return output } |