From fa988f0a34b178233bc02066c7a0086ebe2412f3 Mon Sep 17 00:00:00 2001 From: Zhi Dou Date: Thu, 25 Jul 2024 16:54:50 +0000 Subject: [PATCH] add hide and unsupportedadppusage annotation to read library Test: presubmit Bug: 349874828 Change-Id: I5b808d87fe7df2ba8a85c8c75ee7baa66ff22d6b --- tools/aconfig/aconfig/src/codegen/java.rs | 299 ++++++++++++++---- .../templates/FeatureFlagsImpl.java.template | 4 +- .../aconfig_storage_file/tests/Android.bp | 1 - .../aconfig_storage_read_api/Android.bp | 3 + .../storage/StorageInternalReader.java | 6 + 5 files changed, 252 insertions(+), 61 deletions(-) diff --git a/tools/aconfig/aconfig/src/codegen/java.rs b/tools/aconfig/aconfig/src/codegen/java.rs index 3523b50b7b..419cfa9a18 100644 --- a/tools/aconfig/aconfig/src/codegen/java.rs +++ b/tools/aconfig/aconfig/src/codegen/java.rs @@ -1,18 +1,18 @@ /* - * Copyright (C) 2023 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. - */ +* Copyright (C) 2023 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. +*/ use anyhow::Result; use serde::Serialize; @@ -508,12 +508,15 @@ mod tests { private static FeatureFlags FEATURE_FLAGS = new FeatureFlagsImpl(); }"#; - let expect_featureflagsimpl_content = r#" + let expected_featureflagsmpl_content_0 = r#" package com.android.aconfig.test; // TODO(b/303773055): Remove the annotation after access issue is resolved. import android.compat.annotation.UnsupportedAppUsage; import android.provider.DeviceConfig; import android.provider.DeviceConfig.Properties; + "#; + + let expected_featureflagsmpl_content_1 = r#" /** @hide */ public final class FeatureFlagsImpl implements FeatureFlags { private static boolean aconfig_test_is_cached = false; @@ -522,48 +525,8 @@ mod tests { private static boolean disabledRwExported = false; private static boolean disabledRwInOtherNamespace = false; private static boolean enabledRw = true; - - - private void load_overrides_aconfig_test() { - try { - Properties properties = DeviceConfig.getProperties("aconfig_test"); - disabledRw = - properties.getBoolean(Flags.FLAG_DISABLED_RW, false); - disabledRwExported = - properties.getBoolean(Flags.FLAG_DISABLED_RW_EXPORTED, false); - enabledRw = - properties.getBoolean(Flags.FLAG_ENABLED_RW, true); - } catch (NullPointerException e) { - throw new RuntimeException( - "Cannot read value from namespace aconfig_test " - + "from DeviceConfig. It could be that the code using flag " - + "executed before SettingsProvider initialization. Please use " - + "fixed read-only flag by adding is_fixed_read_only: true in " - + "flag declaration.", - e - ); - } - aconfig_test_is_cached = true; - } - - private void load_overrides_other_namespace() { - try { - Properties properties = DeviceConfig.getProperties("other_namespace"); - disabledRwInOtherNamespace = - properties.getBoolean(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, false); - } catch (NullPointerException e) { - throw new RuntimeException( - "Cannot read value from namespace other_namespace " - + "from DeviceConfig. It could be that the code using flag " - + "executed before SettingsProvider initialization. Please use " - + "fixed read-only flag by adding is_fixed_read_only: true in " - + "flag declaration.", - e - ); - } - other_namespace_is_cached = true; - } - + "#; + let expected_featureflagsmpl_content_2 = r#" @Override @com.android.aconfig.annotations.AconfigFlagAccessor @UnsupportedAppUsage @@ -632,9 +595,229 @@ mod tests { } } "#; + + let expect_featureflagsimpl_content_old = expected_featureflagsmpl_content_0.to_owned() + + expected_featureflagsmpl_content_1 + + r#" + private void load_overrides_aconfig_test() { + try { + Properties properties = DeviceConfig.getProperties("aconfig_test"); + disabledRw = + properties.getBoolean(Flags.FLAG_DISABLED_RW, false); + disabledRwExported = + properties.getBoolean(Flags.FLAG_DISABLED_RW_EXPORTED, false); + enabledRw = + properties.getBoolean(Flags.FLAG_ENABLED_RW, true); + } catch (NullPointerException e) { + throw new RuntimeException( + "Cannot read value from namespace aconfig_test " + + "from DeviceConfig. It could be that the code using flag " + + "executed before SettingsProvider initialization. Please use " + + "fixed read-only flag by adding is_fixed_read_only: true in " + + "flag declaration.", + e + ); + } + aconfig_test_is_cached = true; + } + + private void load_overrides_other_namespace() { + try { + Properties properties = DeviceConfig.getProperties("other_namespace"); + disabledRwInOtherNamespace = + properties.getBoolean(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, false); + } catch (NullPointerException e) { + throw new RuntimeException( + "Cannot read value from namespace other_namespace " + + "from DeviceConfig. It could be that the code using flag " + + "executed before SettingsProvider initialization. Please use " + + "fixed read-only flag by adding is_fixed_read_only: true in " + + "flag declaration.", + e + ); + } + other_namespace_is_cached = true; + }"# + + expected_featureflagsmpl_content_2; + let mut file_set = HashMap::from([ ("com/android/aconfig/test/Flags.java", expect_flags_content.as_str()), - ("com/android/aconfig/test/FeatureFlagsImpl.java", expect_featureflagsimpl_content), + ( + "com/android/aconfig/test/FeatureFlagsImpl.java", + &expect_featureflagsimpl_content_old, + ), + ("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, + ), + ]); + + for file in generated_files { + let file_path = file.path.to_str().unwrap(); + assert!(file_set.contains_key(file_path), "Cannot find {}", file_path); + assert_eq!( + None, + crate::test::first_significant_code_diff( + file_set.get(file_path).unwrap(), + &String::from_utf8(file.contents).unwrap() + ), + "File {} content is not correct", + file_path + ); + file_set.remove(file_path); + } + + assert!(file_set.is_empty()); + + let parsed_flags = crate::test::parse_test_flags(); + let mode = CodegenMode::Production; + let modified_parsed_flags = + crate::commands::modify_parsed_flags_based_on_mode(parsed_flags, mode).unwrap(); + let flag_ids = + assign_flag_ids(crate::test::TEST_PACKAGE, modified_parsed_flags.iter()).unwrap(); + let generated_files = generate_java_code( + crate::test::TEST_PACKAGE, + modified_parsed_flags.into_iter(), + mode, + flag_ids, + true, + ) + .unwrap(); + + let expect_featureflagsimpl_content_new = expected_featureflagsmpl_content_0.to_owned() + + r#" + import android.aconfig.storage.StorageInternalReader; + import android.util.Log; + import java.io.File; + "# + + expected_featureflagsmpl_content_1 + + r#" + StorageInternalReader reader; + boolean readFromNewStorage; + + private final static String TAG = "AconfigJavaCodegen"; + + public FeatureFlagsImpl() { + File file = new File("/metadata/aconfig_test_missions/mission_1"); + if (file.exists()) { + readFromNewStorage = true; + try { + reader = new StorageInternalReader("system", "com.android.aconfig.test"); + } catch (Exception e) { + reader = null; + } + } + } + + private void load_overrides_aconfig_test() { + try { + boolean val; + Properties properties = DeviceConfig.getProperties("aconfig_test"); + disabledRw = + properties.getBoolean(Flags.FLAG_DISABLED_RW, false); + if (readFromNewStorage && reader != null) { + try { + val = reader.getBooleanFlagValue(1); + if (val == disabledRw) { + Log.i(TAG, "success: disabledRw value matches"); + } else { + Log.i(TAG, String.format( + "error: disabledRw value mismatch, new storage value is %s, old storage value is %s", + val, disabledRw)); + } + } catch (Exception e) { + Log.e(TAG, "error: failed to read flag value of disabledRw", e); + } + } + disabledRwExported = + properties.getBoolean(Flags.FLAG_DISABLED_RW_EXPORTED, false); + if (readFromNewStorage && reader != null) { + try { + val = reader.getBooleanFlagValue(2); + if (val == disabledRwExported) { + Log.i(TAG, "success: disabledRwExported value matches"); + } else { + Log.i(TAG, String.format( + "error: disabledRwExported value mismatch, new storage value is %s, old storage value is %s", + val, disabledRwExported)); + } + } catch (Exception e) { + Log.e(TAG, "error: failed to read flag value of disabledRwExported", e); + } + } + enabledRw = + properties.getBoolean(Flags.FLAG_ENABLED_RW, true); + if (readFromNewStorage && reader != null) { + try { + val = reader.getBooleanFlagValue(8); + if (val == enabledRw) { + Log.i(TAG, "success: enabledRw value matches"); + } else { + Log.i(TAG, String.format( + "error: enabledRw value mismatch, new storage value is %s, old storage value is %s", + val, enabledRw)); + } + } catch (Exception e) { + Log.e(TAG, "error: failed to read flag value of enabledRw", e); + } + } + } catch (NullPointerException e) { + throw new RuntimeException( + "Cannot read value from namespace aconfig_test " + + "from DeviceConfig. It could be that the code using flag " + + "executed before SettingsProvider initialization. Please use " + + "fixed read-only flag by adding is_fixed_read_only: true in " + + "flag declaration.", + e + ); + } + aconfig_test_is_cached = true; + } + + private void load_overrides_other_namespace() { + try { + boolean val; + Properties properties = DeviceConfig.getProperties("other_namespace"); + disabledRwInOtherNamespace = + properties.getBoolean(Flags.FLAG_DISABLED_RW_IN_OTHER_NAMESPACE, false); + if (readFromNewStorage && reader != null) { + try { + val = reader.getBooleanFlagValue(3); + if (val == disabledRwInOtherNamespace) { + Log.i(TAG, "success: disabledRwInOtherNamespace value matches"); + } else { + Log.i(TAG, String.format( + "error: disabledRwInOtherNamespace value mismatch, new storage value is %s, old storage value is %s", + val, disabledRwInOtherNamespace)); + } + } catch (Exception e) { + Log.e(TAG, "error: failed to read flag value of disabledRwInOtherNamespace", e); + } + } + } catch (NullPointerException e) { + throw new RuntimeException( + "Cannot read value from namespace other_namespace " + + "from DeviceConfig. It could be that the code using flag " + + "executed before SettingsProvider initialization. Please use " + + "fixed read-only flag by adding is_fixed_read_only: true in " + + "flag declaration.", + e + ); + } + other_namespace_is_cached = true; + }"# + expected_featureflagsmpl_content_2; + + let mut file_set = HashMap::from([ + ("com/android/aconfig/test/Flags.java", expect_flags_content.as_str()), + ( + "com/android/aconfig/test/FeatureFlagsImpl.java", + &expect_featureflagsimpl_content_new, + ), ("com/android/aconfig/test/FeatureFlags.java", EXPECTED_FEATUREFLAGS_COMMON_CONTENT), ( "com/android/aconfig/test/CustomFeatureFlags.java", diff --git a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template index a6e1cf3999..e3b5d8ed15 100644 --- a/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template +++ b/tools/aconfig/aconfig/templates/FeatureFlagsImpl.java.template @@ -45,7 +45,7 @@ public final class FeatureFlagsImpl implements FeatureFlags \{ readFromNewStorage = true; try \{ reader = new StorageInternalReader("{container}", "{package_name}"); - } catch(Exception e) \{ + } catch (Exception e) \{ reader = null; } } @@ -78,7 +78,7 @@ public final class FeatureFlagsImpl implements FeatureFlags \{ val, {flag.method_name})); } } catch (Exception e) \{ - Log.e(TAG,"error: failed to read flag value of {flag.method_name}", e); + Log.e(TAG, "error: failed to read flag value of {flag.method_name}", e); } } {{ -endif }} diff --git a/tools/aconfig/aconfig_storage_file/tests/Android.bp b/tools/aconfig/aconfig_storage_file/tests/Android.bp index c33127fc86..85160d600c 100644 --- a/tools/aconfig/aconfig_storage_file/tests/Android.bp +++ b/tools/aconfig/aconfig_storage_file/tests/Android.bp @@ -32,7 +32,6 @@ android_test { "androidx.test.runner", "junit", ], - sdk_version: "test_current", test_config: "AndroidStorageJaveTest.xml", data: [ "package.map", diff --git a/tools/aconfig/aconfig_storage_read_api/Android.bp b/tools/aconfig/aconfig_storage_read_api/Android.bp index b4bb06f226..163600ab75 100644 --- a/tools/aconfig/aconfig_storage_read_api/Android.bp +++ b/tools/aconfig/aconfig_storage_read_api/Android.bp @@ -171,6 +171,9 @@ java_library { srcs: [ "srcs/android/aconfig/storage/StorageInternalReader.java", ], + libs: [ + "unsupportedappusage", + ], static_libs: [ "aconfig_storage_file_java", ], diff --git a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/StorageInternalReader.java b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/StorageInternalReader.java index 5f31017d21..bbb6813295 100644 --- a/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/StorageInternalReader.java +++ b/tools/aconfig/aconfig_storage_read_api/srcs/android/aconfig/storage/StorageInternalReader.java @@ -16,10 +16,13 @@ package android.aconfig.storage; +import android.compat.annotation.UnsupportedAppUsage; + import java.io.FileInputStream; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; +/** @hide */ public class StorageInternalReader { private static final String MAP_PATH = "/metadata/aconfig/maps/"; @@ -30,16 +33,19 @@ public class StorageInternalReader { private int mPackageBooleanStartOffset; + @UnsupportedAppUsage public StorageInternalReader(String container, String packageName) { this(packageName, MAP_PATH + container + ".package.map", BOOT_PATH + container + ".val"); } + @UnsupportedAppUsage public StorageInternalReader(String packageName, String packageMapFile, String flagValueFile) { mPackageTable = PackageTable.fromBytes(mapStorageFile(packageMapFile)); mFlagValueList = FlagValueList.fromBytes(mapStorageFile(flagValueFile)); mPackageBooleanStartOffset = getPackageBooleanStartOffset(packageName); } + @UnsupportedAppUsage public boolean getBooleanFlagValue(int index) { index += mPackageBooleanStartOffset; if (index >= mFlagValueList.size()) {