Loading Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -294,6 +294,7 @@ java_defaults { srcs: [ ":framework-non-updatable-sources", "core/java/**/*.logtags", ":apex-info-list", ], aidl: { generate_get_transaction_name: true, Loading core/java/com/android/internal/content/om/OverlayConfig.java +49 −6 Original line number Diff line number Diff line Loading @@ -25,17 +25,22 @@ import android.os.Trace; import android.util.ArrayMap; import android.util.Log; import com.android.apex.ApexInfo; import com.android.apex.XmlParser; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.om.OverlayConfigParser.OverlayPartition; import com.android.internal.content.om.OverlayConfigParser.ParsedConfiguration; import com.android.internal.content.om.OverlayScanner.ParsedOverlayInfo; import com.android.internal.util.Preconditions; import com.android.internal.util.function.TriConsumer; import java.io.File; import java.io.FileInputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.function.BiConsumer; import java.util.List; import java.util.function.Supplier; /** Loading Loading @@ -73,7 +78,7 @@ public class OverlayConfig { public interface PackageProvider { /** Performs the given action for each package. */ void forEachPackage(BiConsumer<ParsingPackageRead, Boolean> p); void forEachPackage(TriConsumer<ParsingPackageRead, Boolean, File> p); } private static final Comparator<ParsedConfiguration> sStaticOverlayComparator = (c1, c2) -> { Loading Loading @@ -115,6 +120,8 @@ public class OverlayConfig { p))); } ArrayMap<Integer, List<String>> activeApexesPerPartition = getActiveApexes(partitions); boolean foundConfigFile = false; ArrayList<ParsedOverlayInfo> packageManagerOverlayInfos = null; Loading @@ -123,7 +130,9 @@ public class OverlayConfig { final OverlayPartition partition = partitions.get(i); final OverlayScanner scanner = (scannerFactory == null) ? null : scannerFactory.get(); final ArrayList<ParsedConfiguration> partitionOverlays = OverlayConfigParser.getConfigurations(partition, scanner); OverlayConfigParser.getConfigurations(partition, scanner, activeApexesPerPartition.getOrDefault(partition.type, Collections.emptyList())); if (partitionOverlays != null) { foundConfigFile = true; overlays.addAll(partitionOverlays); Loading @@ -145,7 +154,8 @@ public class OverlayConfig { // Filter out overlays not present in the partition. partitionOverlayInfos = new ArrayList<>(packageManagerOverlayInfos); for (int j = partitionOverlayInfos.size() - 1; j >= 0; j--) { if (!partition.containsFile(partitionOverlayInfos.get(j).path)) { if (!partition.containsFile(partitionOverlayInfos.get(j) .getOriginalPartitionPath())) { partitionOverlayInfos.remove(j); } } Loading Loading @@ -292,16 +302,49 @@ public class OverlayConfig { private static ArrayList<ParsedOverlayInfo> getOverlayPackageInfos( @NonNull PackageProvider packageManager) { final ArrayList<ParsedOverlayInfo> overlays = new ArrayList<>(); packageManager.forEachPackage((ParsingPackageRead p, Boolean isSystem) -> { packageManager.forEachPackage((ParsingPackageRead p, Boolean isSystem, @Nullable File preInstalledApexPath) -> { if (p.getOverlayTarget() != null && isSystem) { overlays.add(new ParsedOverlayInfo(p.getPackageName(), p.getOverlayTarget(), p.getTargetSdkVersion(), p.isOverlayIsStatic(), p.getOverlayPriority(), new File(p.getBaseApkPath()))); new File(p.getBaseApkPath()), preInstalledApexPath)); } }); return overlays; } /** Returns a map of PartitionType to List of active APEX module names. */ @NonNull private static ArrayMap<Integer, List<String>> getActiveApexes( @NonNull List<OverlayPartition> partitions) { // An Overlay in an APEX, which is an update of an APEX in a given partition, // is considered as belonging to that partition. ArrayMap<Integer, List<String>> result = new ArrayMap<>(); for (OverlayPartition partition : partitions) { result.put(partition.type, new ArrayList<String>()); } // Read from apex-info-list because ApexManager is not accessible to zygote. File apexInfoList = new File("/apex/apex-info-list.xml"); if (apexInfoList.exists() && apexInfoList.canRead()) { try (FileInputStream stream = new FileInputStream(apexInfoList)) { List<ApexInfo> apexInfos = XmlParser.readApexInfoList(stream).getApexInfo(); for (ApexInfo info : apexInfos) { if (info.getIsActive()) { for (OverlayPartition partition : partitions) { if (partition.containsPath(info.getPreinstalledModulePath())) { result.get(partition.type).add(info.getModuleName()); break; } } } } } catch (Exception e) { Log.w(TAG, "Error reading apex-info-list: " + e); } } return result; } /** Represents a single call to idmap create-multiple. */ @VisibleForTesting public static class IdmapInvocation { Loading core/java/com/android/internal/content/om/OverlayConfigParser.java +12 −5 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * Responsible for parsing configurations of Runtime Resource Overlays that control mutability, Loading Loading @@ -192,14 +193,20 @@ final class OverlayConfigParser { */ @Nullable static ArrayList<ParsedConfiguration> getConfigurations( @NonNull OverlayPartition partition, @Nullable OverlayScanner scanner) { if (partition.getOverlayFolder() == null) { return null; } @NonNull OverlayPartition partition, @Nullable OverlayScanner scanner, @NonNull List<String> activeApexes) { if (scanner != null) { if (partition.getOverlayFolder() != null) { scanner.scanDir(partition.getOverlayFolder()); } for (String apex : activeApexes) { scanner.scanDir(new File("/apex/" + apex + "/overlay/")); } } if (partition.getOverlayFolder() == null) { return null; } final File configFile = new File(partition.getOverlayFolder(), CONFIG_DEFAULT_FILENAME); if (!configFile.exists()) { Loading core/java/com/android/internal/content/om/OverlayScanner.java +19 −4 Original line number Diff line number Diff line Loading @@ -47,23 +47,38 @@ public class OverlayScanner { public final boolean isStatic; public final int priority; public final File path; @Nullable public final File preInstalledApexPath; public ParsedOverlayInfo(String packageName, String targetPackageName, int targetSdkVersion, boolean isStatic, int priority, File path) { int targetSdkVersion, boolean isStatic, int priority, File path, @Nullable File preInstalledApexPath) { this.packageName = packageName; this.targetPackageName = targetPackageName; this.targetSdkVersion = targetSdkVersion; this.isStatic = isStatic; this.priority = priority; this.path = path; this.preInstalledApexPath = preInstalledApexPath; } @Override public String toString() { return getClass().getSimpleName() + String.format("{packageName=%s" + ", targetPackageName=%s, targetSdkVersion=%s, isStatic=%s" + ", priority=%s, path=%s}", packageName, targetPackageName, targetSdkVersion, isStatic, priority, path); + ", priority=%s, path=%s, preInstalledApexPath=%s}", packageName, targetPackageName, targetSdkVersion, isStatic, priority, path, preInstalledApexPath); } /** * Retrieves the path of the overlay in its original installation partition. * * An Overlay in an APEX, which is an update of an APEX in a given partition, * is considered as belonging to that partition. */ @NonNull public File getOriginalPartitionPath() { return preInstalledApexPath != null ? preInstalledApexPath : path; } } Loading Loading @@ -138,6 +153,6 @@ public class OverlayScanner { return apkLite.getTargetPackageName() == null ? null : new ParsedOverlayInfo(apkLite.getPackageName(), apkLite.getTargetPackageName(), apkLite.getTargetSdkVersion(), apkLite.isOverlayIsStatic(), apkLite.getOverlayPriority(), new File(apkLite.getPath())); apkLite.getOverlayPriority(), new File(apkLite.getPath()), null); } } core/jni/fd_utils.cpp +8 −0 Original line number Diff line number Diff line Loading @@ -138,6 +138,14 @@ bool FileDescriptorAllowlist::IsAllowed(const std::string& path) const { return true; } // Allow Runtime Resource Overlays inside APEXes. static const char* kOverlayPathSuffix = "/overlay"; if (android::base::StartsWith(path, kApexPrefix) && android::base::EndsWith(android::base::Dirname(path), kOverlayPathSuffix) && android::base::EndsWith(path, kApkSuffix) && path.find("/../") == std::string::npos) { return true; } static const char* kOverlayIdmapPrefix = "/data/resource-cache/"; static const char* kOverlayIdmapSuffix = ".apk@idmap"; if (android::base::StartsWith(path, kOverlayIdmapPrefix) && Loading Loading
Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -294,6 +294,7 @@ java_defaults { srcs: [ ":framework-non-updatable-sources", "core/java/**/*.logtags", ":apex-info-list", ], aidl: { generate_get_transaction_name: true, Loading
core/java/com/android/internal/content/om/OverlayConfig.java +49 −6 Original line number Diff line number Diff line Loading @@ -25,17 +25,22 @@ import android.os.Trace; import android.util.ArrayMap; import android.util.Log; import com.android.apex.ApexInfo; import com.android.apex.XmlParser; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.om.OverlayConfigParser.OverlayPartition; import com.android.internal.content.om.OverlayConfigParser.ParsedConfiguration; import com.android.internal.content.om.OverlayScanner.ParsedOverlayInfo; import com.android.internal.util.Preconditions; import com.android.internal.util.function.TriConsumer; import java.io.File; import java.io.FileInputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.function.BiConsumer; import java.util.List; import java.util.function.Supplier; /** Loading Loading @@ -73,7 +78,7 @@ public class OverlayConfig { public interface PackageProvider { /** Performs the given action for each package. */ void forEachPackage(BiConsumer<ParsingPackageRead, Boolean> p); void forEachPackage(TriConsumer<ParsingPackageRead, Boolean, File> p); } private static final Comparator<ParsedConfiguration> sStaticOverlayComparator = (c1, c2) -> { Loading Loading @@ -115,6 +120,8 @@ public class OverlayConfig { p))); } ArrayMap<Integer, List<String>> activeApexesPerPartition = getActiveApexes(partitions); boolean foundConfigFile = false; ArrayList<ParsedOverlayInfo> packageManagerOverlayInfos = null; Loading @@ -123,7 +130,9 @@ public class OverlayConfig { final OverlayPartition partition = partitions.get(i); final OverlayScanner scanner = (scannerFactory == null) ? null : scannerFactory.get(); final ArrayList<ParsedConfiguration> partitionOverlays = OverlayConfigParser.getConfigurations(partition, scanner); OverlayConfigParser.getConfigurations(partition, scanner, activeApexesPerPartition.getOrDefault(partition.type, Collections.emptyList())); if (partitionOverlays != null) { foundConfigFile = true; overlays.addAll(partitionOverlays); Loading @@ -145,7 +154,8 @@ public class OverlayConfig { // Filter out overlays not present in the partition. partitionOverlayInfos = new ArrayList<>(packageManagerOverlayInfos); for (int j = partitionOverlayInfos.size() - 1; j >= 0; j--) { if (!partition.containsFile(partitionOverlayInfos.get(j).path)) { if (!partition.containsFile(partitionOverlayInfos.get(j) .getOriginalPartitionPath())) { partitionOverlayInfos.remove(j); } } Loading Loading @@ -292,16 +302,49 @@ public class OverlayConfig { private static ArrayList<ParsedOverlayInfo> getOverlayPackageInfos( @NonNull PackageProvider packageManager) { final ArrayList<ParsedOverlayInfo> overlays = new ArrayList<>(); packageManager.forEachPackage((ParsingPackageRead p, Boolean isSystem) -> { packageManager.forEachPackage((ParsingPackageRead p, Boolean isSystem, @Nullable File preInstalledApexPath) -> { if (p.getOverlayTarget() != null && isSystem) { overlays.add(new ParsedOverlayInfo(p.getPackageName(), p.getOverlayTarget(), p.getTargetSdkVersion(), p.isOverlayIsStatic(), p.getOverlayPriority(), new File(p.getBaseApkPath()))); new File(p.getBaseApkPath()), preInstalledApexPath)); } }); return overlays; } /** Returns a map of PartitionType to List of active APEX module names. */ @NonNull private static ArrayMap<Integer, List<String>> getActiveApexes( @NonNull List<OverlayPartition> partitions) { // An Overlay in an APEX, which is an update of an APEX in a given partition, // is considered as belonging to that partition. ArrayMap<Integer, List<String>> result = new ArrayMap<>(); for (OverlayPartition partition : partitions) { result.put(partition.type, new ArrayList<String>()); } // Read from apex-info-list because ApexManager is not accessible to zygote. File apexInfoList = new File("/apex/apex-info-list.xml"); if (apexInfoList.exists() && apexInfoList.canRead()) { try (FileInputStream stream = new FileInputStream(apexInfoList)) { List<ApexInfo> apexInfos = XmlParser.readApexInfoList(stream).getApexInfo(); for (ApexInfo info : apexInfos) { if (info.getIsActive()) { for (OverlayPartition partition : partitions) { if (partition.containsPath(info.getPreinstalledModulePath())) { result.get(partition.type).add(info.getModuleName()); break; } } } } } catch (Exception e) { Log.w(TAG, "Error reading apex-info-list: " + e); } } return result; } /** Represents a single call to idmap create-multiple. */ @VisibleForTesting public static class IdmapInvocation { Loading
core/java/com/android/internal/content/om/OverlayConfigParser.java +12 −5 Original line number Diff line number Diff line Loading @@ -40,6 +40,7 @@ import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * Responsible for parsing configurations of Runtime Resource Overlays that control mutability, Loading Loading @@ -192,14 +193,20 @@ final class OverlayConfigParser { */ @Nullable static ArrayList<ParsedConfiguration> getConfigurations( @NonNull OverlayPartition partition, @Nullable OverlayScanner scanner) { if (partition.getOverlayFolder() == null) { return null; } @NonNull OverlayPartition partition, @Nullable OverlayScanner scanner, @NonNull List<String> activeApexes) { if (scanner != null) { if (partition.getOverlayFolder() != null) { scanner.scanDir(partition.getOverlayFolder()); } for (String apex : activeApexes) { scanner.scanDir(new File("/apex/" + apex + "/overlay/")); } } if (partition.getOverlayFolder() == null) { return null; } final File configFile = new File(partition.getOverlayFolder(), CONFIG_DEFAULT_FILENAME); if (!configFile.exists()) { Loading
core/java/com/android/internal/content/om/OverlayScanner.java +19 −4 Original line number Diff line number Diff line Loading @@ -47,23 +47,38 @@ public class OverlayScanner { public final boolean isStatic; public final int priority; public final File path; @Nullable public final File preInstalledApexPath; public ParsedOverlayInfo(String packageName, String targetPackageName, int targetSdkVersion, boolean isStatic, int priority, File path) { int targetSdkVersion, boolean isStatic, int priority, File path, @Nullable File preInstalledApexPath) { this.packageName = packageName; this.targetPackageName = targetPackageName; this.targetSdkVersion = targetSdkVersion; this.isStatic = isStatic; this.priority = priority; this.path = path; this.preInstalledApexPath = preInstalledApexPath; } @Override public String toString() { return getClass().getSimpleName() + String.format("{packageName=%s" + ", targetPackageName=%s, targetSdkVersion=%s, isStatic=%s" + ", priority=%s, path=%s}", packageName, targetPackageName, targetSdkVersion, isStatic, priority, path); + ", priority=%s, path=%s, preInstalledApexPath=%s}", packageName, targetPackageName, targetSdkVersion, isStatic, priority, path, preInstalledApexPath); } /** * Retrieves the path of the overlay in its original installation partition. * * An Overlay in an APEX, which is an update of an APEX in a given partition, * is considered as belonging to that partition. */ @NonNull public File getOriginalPartitionPath() { return preInstalledApexPath != null ? preInstalledApexPath : path; } } Loading Loading @@ -138,6 +153,6 @@ public class OverlayScanner { return apkLite.getTargetPackageName() == null ? null : new ParsedOverlayInfo(apkLite.getPackageName(), apkLite.getTargetPackageName(), apkLite.getTargetSdkVersion(), apkLite.isOverlayIsStatic(), apkLite.getOverlayPriority(), new File(apkLite.getPath())); apkLite.getOverlayPriority(), new File(apkLite.getPath()), null); } }
core/jni/fd_utils.cpp +8 −0 Original line number Diff line number Diff line Loading @@ -138,6 +138,14 @@ bool FileDescriptorAllowlist::IsAllowed(const std::string& path) const { return true; } // Allow Runtime Resource Overlays inside APEXes. static const char* kOverlayPathSuffix = "/overlay"; if (android::base::StartsWith(path, kApexPrefix) && android::base::EndsWith(android::base::Dirname(path), kOverlayPathSuffix) && android::base::EndsWith(path, kApkSuffix) && path.find("/../") == std::string::npos) { return true; } static const char* kOverlayIdmapPrefix = "/data/resource-cache/"; static const char* kOverlayIdmapSuffix = ".apk@idmap"; if (android::base::StartsWith(path, kOverlayIdmapPrefix) && Loading