From 2f3a9c61f771790f0d59fc6b9991d63cfddbf2c7 Mon Sep 17 00:00:00 2001 From: John Wu Date: Sat, 23 Nov 2024 00:29:29 +0000 Subject: [Ravenwood] Update system property handling - Split out "core" system properties (the default properties we set during the global initialization) and "test" system properties (the properties defined and set through RavenwoodRule) - Reset only the "test" system properties before each test execution - Update the implementation to support nested RavenwoodRule in the future Flag: EXEMPT host test change only Bug: 377765941 Test: $ANDROID_BUILD_TOP/frameworks/base/ravenwood/scripts/run-ravenwood-tests.sh Change-Id: Ia9a2ee217aa89e0f2565d14fb26e3842947e9dc7 --- .../platform/test/ravenwood/RavenwoodRule.java | 10 +- .../test/ravenwood/RavenwoodSystemProperties.java | 248 --------------------- .../test/ravenwood/RavenwoodTestProperties.java | 59 +++++ 3 files changed, 64 insertions(+), 253 deletions(-) delete mode 100644 ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java create mode 100644 ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodTestProperties.java (limited to 'ravenwood/junit-src') diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java index 6262ad160c0f..e49d3d934e9f 100644 --- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java +++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java @@ -92,7 +92,7 @@ public final class RavenwoodRule implements TestRule { } } - final RavenwoodSystemProperties mSystemProperties = new RavenwoodSystemProperties(); + final RavenwoodTestProperties mProperties = new RavenwoodTestProperties(); public static class Builder { @@ -144,8 +144,8 @@ public final class RavenwoodRule implements TestRule { * Has no effect on non-Ravenwood environments. */ public Builder setSystemPropertyImmutable(@NonNull String key, @Nullable Object value) { - mRule.mSystemProperties.setValue(key, value); - mRule.mSystemProperties.setAccessReadOnly(key); + mRule.mProperties.setValue(key, value); + mRule.mProperties.setAccessReadOnly(key); return this; } @@ -160,8 +160,8 @@ public final class RavenwoodRule implements TestRule { * Has no effect on non-Ravenwood environments. */ public Builder setSystemPropertyMutable(@NonNull String key, @Nullable Object value) { - mRule.mSystemProperties.setValue(key, value); - mRule.mSystemProperties.setAccessReadWrite(key); + mRule.mProperties.setValue(key, value); + mRule.mProperties.setAccessReadWrite(key); return this; } diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java deleted file mode 100644 index 9bd376a76f77..000000000000 --- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * 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.platform.test.ravenwood; - -import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_VERBOSE_LOGGING; -import static com.android.ravenwood.common.RavenwoodCommonUtils.getRavenwoodRuntimePath; - -import android.util.Log; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; - -public class RavenwoodSystemProperties { - private static final String TAG = "RavenwoodSystemProperties"; - - /** We pull in propeties from this file. */ - private static final String RAVENWOOD_BUILD_PROP = "ravenwood-data/ravenwood-build.prop"; - - /** This is the actual build.prop we use to build the device (contents depends on lunch). */ - private static final String DEVICE_BUILD_PROP = "ravenwood-data/build.prop"; - - /** The default values. */ - private static final Map sDefaultValues = new HashMap<>(); - - private static final String[] PARTITIONS = { - "bootimage", - "odm", - "product", - "system", - "system_ext", - "vendor", - "vendor_dlkm", - }; - - static Map readProperties(String propFile) { - // Use an ordered map just for cleaner dump log. - final Map ret = new LinkedHashMap<>(); - try { - Files.readAllLines(Path.of(propFile)).stream() - .map(String::trim) - .filter(s -> !s.startsWith("#")) - .map(s -> s.split("\\s*=\\s*", 2)) - .filter(a -> a.length == 2 && a[1].length() > 0) - .forEach(a -> ret.put(a[0], a[1])); - } catch (IOException e) { - throw new RuntimeException(e); - } - return ret; - } - - /** - * Load default sysprops from {@link #RAVENWOOD_BUILD_PROP}. We also pull in - * certain properties from the acutual device's build.prop {@link #DEVICE_BUILD_PROP} too. - * - * More info about property file loading: system/core/init/property_service.cpp - * In the following logic, the only partition we would need to consider is "system", - * since we only read from system-build.prop - */ - static void initialize() { - var path = getRavenwoodRuntimePath(); - var ravenwoodProps = readProperties(path + RAVENWOOD_BUILD_PROP); - var deviceProps = readProperties(path + DEVICE_BUILD_PROP); - - Log.i(TAG, "Default system properties:"); - ravenwoodProps.forEach((key, origValue) -> { - final String value; - - // If a value starts with "$$$", then this is a reference to the device-side value. - if (origValue.startsWith("$$$")) { - var deviceKey = origValue.substring(3); - var deviceValue = deviceProps.get(deviceKey); - if (deviceValue == null) { - throw new RuntimeException("Failed to initialize system properties. Key '" - + deviceKey + "' doesn't exist in the device side build.prop"); - } - value = deviceValue; - } else { - value = origValue; - } - Log.i(TAG, key + "=" + value); - sDefaultValues.put(key, value); - }); - - // Copy ro.product.* and ro.build.* to all partitions, just in case - // We don't want to log these because these are just a lot of duplicate values - for (var entry : Set.copyOf(sDefaultValues.entrySet())) { - var key = entry.getKey(); - if (key.startsWith("ro.product.") || key.startsWith("ro.build.")) { - var name = key.substring(3); - for (String partition : PARTITIONS) { - var newKey = "ro." + partition + "." + name; - if (!sDefaultValues.containsKey(newKey)) { - sDefaultValues.put(newKey, entry.getValue()); - } - } - } - } - if (RAVENWOOD_VERBOSE_LOGGING) { - // Dump all properties for local debugging. - Log.v(TAG, "All system properties:"); - for (var key : sDefaultValues.keySet().stream().sorted().toList()) { - Log.v(TAG, "" + key + "=" + sDefaultValues.get(key)); - } - } - } - - private volatile boolean mIsImmutable; - - private final Map mValues = new HashMap<>(); - - /** Set of additional keys that should be considered readable */ - private final Set mKeyReadable = new HashSet<>(); - - /** Set of additional keys that should be considered writable */ - private final Set mKeyWritable = new HashSet<>(); - - public RavenwoodSystemProperties() { - mValues.putAll(sDefaultValues); - } - - /** Copy constructor */ - public RavenwoodSystemProperties(RavenwoodSystemProperties source, boolean immutable) { - mKeyReadable.addAll(source.mKeyReadable); - mKeyWritable.addAll(source.mKeyWritable); - mValues.putAll(source.mValues); - mIsImmutable = immutable; - } - - public Map getValues() { - return new HashMap<>(mValues); - } - - public boolean isKeyReadable(String key) { - final String root = getKeyRoot(key); - - if (root.startsWith("debug.")) return true; - - // This set is carefully curated to help identify situations where a test may - // accidentally depend on a default value of an obscure property whose owner hasn't - // decided how Ravenwood should behave. - if (root.startsWith("boot.")) return true; - if (root.startsWith("build.")) return true; - if (root.startsWith("product.")) return true; - if (root.startsWith("soc.")) return true; - if (root.startsWith("system.")) return true; - - // For PropertyInvalidatedCache - if (root.startsWith("cache_key.")) return true; - - switch (key) { - case "gsm.version.baseband": - case "no.such.thing": - case "qemu.sf.lcd_density": - case "ro.bootloader": - case "ro.debuggable": - case "ro.hardware": - case "ro.hw_timeout_multiplier": - case "ro.odm.build.media_performance_class": - case "ro.sf.lcd_density": - case "ro.treble.enabled": - case "ro.vndk.version": - case "ro.icu.data.path": - return true; - } - - return mKeyReadable.contains(key); - } - - public boolean isKeyWritable(String key) { - final String root = getKeyRoot(key); - - if (root.startsWith("debug.")) return true; - - // For PropertyInvalidatedCache - if (root.startsWith("cache_key.")) return true; - - return mKeyWritable.contains(key); - } - - private void ensureNotImmutable() { - if (mIsImmutable) { - throw new RuntimeException("Unable to update immutable instance"); - } - } - - public void setValue(String key, Object value) { - ensureNotImmutable(); - - final String valueString = (value == null) ? null : String.valueOf(value); - if ((valueString == null) || valueString.isEmpty()) { - mValues.remove(key); - } else { - mValues.put(key, valueString); - } - } - - public void setAccessNone(String key) { - ensureNotImmutable(); - mKeyReadable.remove(key); - mKeyWritable.remove(key); - } - - public void setAccessReadOnly(String key) { - ensureNotImmutable(); - mKeyReadable.add(key); - mKeyWritable.remove(key); - } - - public void setAccessReadWrite(String key) { - ensureNotImmutable(); - mKeyReadable.add(key); - mKeyWritable.add(key); - } - - /** - * Return the "root" of the given property key, stripping away any modifier prefix such as - * {@code ro.} or {@code persist.}. - */ - private static String getKeyRoot(String key) { - if (key.startsWith("ro.")) { - return key.substring(3); - } else if (key.startsWith("persist.")) { - return key.substring(8); - } else { - return key; - } - } -} diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodTestProperties.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodTestProperties.java new file mode 100644 index 000000000000..66a26b511213 --- /dev/null +++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodTestProperties.java @@ -0,0 +1,59 @@ +/* + * 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.platform.test.ravenwood; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * A class to store system properties defined by tests. + */ +public class RavenwoodTestProperties { + final Map mValues = new HashMap<>(); + + /** Set of additional keys that should be considered readable */ + final Set mKeyReadable = new HashSet<>(); + + /** Set of additional keys that should be considered writable */ + final Set mKeyWritable = new HashSet<>(); + + public void setValue(String key, Object value) { + final String valueString = (value == null) ? null : String.valueOf(value); + if ((valueString == null) || valueString.isEmpty()) { + mValues.remove(key); + } else { + mValues.put(key, valueString); + } + } + + public void setAccessNone(String key) { + mKeyReadable.remove(key); + mKeyWritable.remove(key); + } + + public void setAccessReadOnly(String key) { + mKeyReadable.add(key); + mKeyWritable.remove(key); + } + + public void setAccessReadWrite(String key) { + mKeyReadable.add(key); + mKeyWritable.add(key); + } +} -- cgit v1.2.3-59-g8ed1b