diff options
Diffstat (limited to 'core/java/com/android/internal/content/om/OverlayConfigParser.java')
-rw-r--r-- | core/java/com/android/internal/content/om/OverlayConfigParser.java | 101 |
1 files changed, 98 insertions, 3 deletions
diff --git a/core/java/com/android/internal/content/om/OverlayConfigParser.java b/core/java/com/android/internal/content/om/OverlayConfigParser.java index faaf7d5cef18..8132652ed6f4 100644 --- a/core/java/com/android/internal/content/om/OverlayConfigParser.java +++ b/core/java/com/android/internal/content/om/OverlayConfigParser.java @@ -24,6 +24,8 @@ import android.content.pm.PackagePartitions; import android.content.pm.PackagePartitions.SystemPartition; import android.os.Build; import android.os.FileUtils; +import android.os.SystemProperties; +import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; import android.util.Xml; @@ -241,6 +243,18 @@ public final class OverlayConfigParser { } } + @FunctionalInterface + public interface SysPropWrapper{ + /** + * Get system property + * + * @param property the key to look up. + * + * @return The property value if found, empty string otherwise. + */ + String get(String property); + } + /** * Retrieves overlays configured within the partition in increasing priority order. * @@ -320,6 +334,76 @@ public final class OverlayConfigParser { } /** + * Expand the property inside a rro configuration path. + * + * A RRO configuration can contain a property, this method expands + * the property to its value. + * + * Only read only properties allowed, prefixed with ro. Other + * properties will raise exception. + * + * Only a single property in the path is allowed. + * + * Example "${ro.boot.hardware.sku}/config.xml" would expand to + * "G020N/config.xml" + * + * @param configPath path to expand + * @param sysPropWrapper method used for reading properties + * + * @return The expanded path. Returns null if configPath is null. + */ + @VisibleForTesting + public static String expandProperty(String configPath, + SysPropWrapper sysPropWrapper) { + if (configPath == null) { + return null; + } + + int propStartPos = configPath.indexOf("${"); + if (propStartPos == -1) { + // No properties inside the string, return as is + return configPath; + } + + final StringBuilder sb = new StringBuilder(); + sb.append(configPath.substring(0, propStartPos)); + + // Read out the end position + int propEndPos = configPath.indexOf("}", propStartPos); + if (propEndPos == -1) { + throw new IllegalStateException("Malformed property, unmatched braces, in: " + + configPath); + } + + // Confirm that there is only one property inside the string + if (configPath.indexOf("${", propStartPos + 2) != -1) { + throw new IllegalStateException("Only a single property supported in path: " + + configPath); + } + + final String propertyName = configPath.substring(propStartPos + 2, propEndPos); + if (!propertyName.startsWith("ro.")) { + throw new IllegalStateException("Only read only properties can be used when " + + "merging RRO config files: " + propertyName); + } + final String propertyValue = sysPropWrapper.get(propertyName); + if (TextUtils.isEmpty(propertyValue)) { + throw new IllegalStateException("Property is empty or doesn't exist: " + propertyName); + } + Log.d(TAG, String.format("Using property in overlay config path: \"%s\"", propertyName)); + sb.append(propertyValue); + + // propEndPos points to '}', need to step to next character, might be outside of string + propEndPos = propEndPos + 1; + // Append the remainder, if exists + if (propEndPos < configPath.length()) { + sb.append(configPath.substring(propEndPos)); + } + + return sb.toString(); + } + + /** * Parses a <merge> tag within an overlay configuration file. * * Merge tags allow for other configuration files to be "merged" at the current parsing @@ -331,10 +415,21 @@ public final class OverlayConfigParser { @Nullable OverlayScanner scanner, @Nullable Map<String, ParsedOverlayInfo> packageManagerOverlayInfos, @NonNull ParsingContext parsingContext) { - final String path = parser.getAttributeValue(null, "path"); + final String path; + + try { + SysPropWrapper sysPropWrapper = p -> { + return SystemProperties.get(p, ""); + }; + path = expandProperty(parser.getAttributeValue(null, "path"), sysPropWrapper); + } catch (IllegalStateException e) { + throw new IllegalStateException(String.format("<merge> path expand error in %s at %s", + configFile, parser.getPositionDescription()), e); + } + if (path == null) { - throw new IllegalStateException(String.format("<merge> without path in %s at %s" - + configFile, parser.getPositionDescription())); + throw new IllegalStateException(String.format("<merge> without path in %s at %s", + configFile, parser.getPositionDescription())); } if (path.startsWith("/")) { |