1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.platform.test.ravenwood; 18 19 import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_SYSPROP; 20 21 import java.util.HashMap; 22 import java.util.HashSet; 23 import java.util.Map; 24 import java.util.Set; 25 import java.util.function.Predicate; 26 27 public class RavenwoodSystemProperties { 28 private volatile boolean mIsImmutable; 29 30 private final Map<String, String> mValues = new HashMap<>(); 31 32 /** Set of additional keys that should be considered readable */ 33 private final Set<String> mKeyReadable = new HashSet<>(); 34 private final Predicate<String> mKeyReadablePredicate = (key) -> { 35 final String root = getKeyRoot(key); 36 37 if (root.startsWith("debug.")) return true; 38 39 // This set is carefully curated to help identify situations where a test may 40 // accidentally depend on a default value of an obscure property whose owner hasn't 41 // decided how Ravenwood should behave. 42 if (root.startsWith("boot.")) return true; 43 if (root.startsWith("build.")) return true; 44 if (root.startsWith("product.")) return true; 45 if (root.startsWith("soc.")) return true; 46 if (root.startsWith("system.")) return true; 47 48 switch (key) { 49 case "gsm.version.baseband": 50 case "no.such.thing": 51 case "ro.bootloader": 52 case "ro.debuggable": 53 case "ro.hardware": 54 case "ro.hw_timeout_multiplier": 55 case "ro.odm.build.media_performance_class": 56 case "ro.treble.enabled": 57 case "ro.vndk.version": 58 return true; 59 } 60 61 return mKeyReadable.contains(key); 62 }; 63 64 /** Set of additional keys that should be considered writable */ 65 private final Set<String> mKeyWritable = new HashSet<>(); 66 private final Predicate<String> mKeyWritablePredicate = (key) -> { 67 final String root = getKeyRoot(key); 68 69 if (root.startsWith("debug.")) return true; 70 71 return mKeyWritable.contains(key); 72 }; 73 RavenwoodSystemProperties()74 public RavenwoodSystemProperties() { 75 // TODO: load these values from build.prop generated files 76 setValueForPartitions("product.brand", "Android"); 77 setValueForPartitions("product.device", "Ravenwood"); 78 setValueForPartitions("product.manufacturer", "Android"); 79 setValueForPartitions("product.model", "Ravenwood"); 80 setValueForPartitions("product.name", "Ravenwood"); 81 82 setValueForPartitions("product.cpu.abilist", "x86_64"); 83 setValueForPartitions("product.cpu.abilist32", ""); 84 setValueForPartitions("product.cpu.abilist64", "x86_64"); 85 86 setValueForPartitions("build.date", "Thu Jan 01 00:00:00 GMT 2024"); 87 setValueForPartitions("build.date.utc", "1704092400"); 88 setValueForPartitions("build.id", "MAIN"); 89 setValueForPartitions("build.tags", "dev-keys"); 90 setValueForPartitions("build.type", "userdebug"); 91 setValueForPartitions("build.version.all_codenames", "REL"); 92 setValueForPartitions("build.version.codename", "REL"); 93 setValueForPartitions("build.version.incremental", "userdebug.ravenwood.20240101"); 94 setValueForPartitions("build.version.known_codenames", "REL"); 95 setValueForPartitions("build.version.release", "14"); 96 setValueForPartitions("build.version.release_or_codename", "VanillaIceCream"); 97 setValueForPartitions("build.version.sdk", "34"); 98 99 setValue("ro.board.first_api_level", "1"); 100 setValue("ro.product.first_api_level", "1"); 101 102 setValue("ro.soc.manufacturer", "Android"); 103 setValue("ro.soc.model", "Ravenwood"); 104 105 setValue("ro.debuggable", "1"); 106 107 setValue(RAVENWOOD_SYSPROP, "1"); 108 } 109 110 /** Copy constructor */ RavenwoodSystemProperties(RavenwoodSystemProperties source, boolean immutable)111 public RavenwoodSystemProperties(RavenwoodSystemProperties source, boolean immutable) { 112 this.mKeyReadable.addAll(source.mKeyReadable); 113 this.mKeyWritable.addAll(source.mKeyWritable); 114 this.mValues.putAll(source.mValues); 115 this.mIsImmutable = immutable; 116 } 117 getValues()118 public Map<String, String> getValues() { 119 return new HashMap<>(mValues); 120 } 121 getKeyReadablePredicate()122 public Predicate<String> getKeyReadablePredicate() { 123 return mKeyReadablePredicate; 124 } 125 getKeyWritablePredicate()126 public Predicate<String> getKeyWritablePredicate() { 127 return mKeyWritablePredicate; 128 } 129 130 private static final String[] PARTITIONS = { 131 "bootimage", 132 "odm", 133 "product", 134 "system", 135 "system_ext", 136 "vendor", 137 "vendor_dlkm", 138 }; 139 ensureNotImmutable()140 private void ensureNotImmutable() { 141 if (mIsImmutable) { 142 throw new RuntimeException("Unable to update immutable instance"); 143 } 144 } 145 146 /** 147 * Set the given property for all possible partitions where it could be defined. For 148 * example, the value of {@code ro.build.type} is typically also mirrored under 149 * {@code ro.system.build.type}, etc. 150 */ setValueForPartitions(String key, String value)151 private void setValueForPartitions(String key, String value) { 152 ensureNotImmutable(); 153 154 setValue("ro." + key, value); 155 for (String partition : PARTITIONS) { 156 setValue("ro." + partition + "." + key, value); 157 } 158 } 159 setValue(String key, Object value)160 public void setValue(String key, Object value) { 161 ensureNotImmutable(); 162 163 final String valueString = (value == null) ? null : String.valueOf(value); 164 if ((valueString == null) || valueString.isEmpty()) { 165 mValues.remove(key); 166 } else { 167 mValues.put(key, valueString); 168 } 169 } 170 setAccessNone(String key)171 public void setAccessNone(String key) { 172 ensureNotImmutable(); 173 mKeyReadable.remove(key); 174 mKeyWritable.remove(key); 175 } 176 setAccessReadOnly(String key)177 public void setAccessReadOnly(String key) { 178 ensureNotImmutable(); 179 mKeyReadable.add(key); 180 mKeyWritable.remove(key); 181 } 182 setAccessReadWrite(String key)183 public void setAccessReadWrite(String key) { 184 ensureNotImmutable(); 185 mKeyReadable.add(key); 186 mKeyWritable.add(key); 187 } 188 189 /** 190 * Return the "root" of the given property key, stripping away any modifier prefix such as 191 * {@code ro.} or {@code persist.}. 192 */ getKeyRoot(String key)193 private static String getKeyRoot(String key) { 194 if (key.startsWith("ro.")) { 195 return key.substring(3); 196 } else if (key.startsWith("persist.")) { 197 return key.substring(8); 198 } else { 199 return key; 200 } 201 } 202 203 /** 204 * Return an immutable, default instance. 205 */ 206 // Create a default instance, and make an immutable copy of it. 207 public static final RavenwoodSystemProperties DEFAULT_VALUES = 208 new RavenwoodSystemProperties(new RavenwoodSystemProperties(), true); 209 }