Loading Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -297,6 +297,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 +50 −6 Original line number Diff line number Diff line Loading @@ -26,20 +26,25 @@ import android.util.ArrayMap; import android.util.IndentingPrintWriter; 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.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.BiConsumer; import java.util.function.Supplier; /** Loading Loading @@ -77,7 +82,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 @@ -119,6 +124,8 @@ public class OverlayConfig { p))); } ArrayMap<Integer, List<String>> activeApexesPerPartition = getActiveApexes(partitions); boolean foundConfigFile = false; final Map<String, ParsedOverlayInfo> packageManagerOverlayInfos = packageProvider == null ? null : getOverlayPackageInfos(packageProvider); Loading @@ -129,7 +136,9 @@ public class OverlayConfig { final OverlayScanner scanner = (scannerFactory == null) ? null : scannerFactory.get(); final ArrayList<ParsedConfiguration> partitionOverlays = OverlayConfigParser.getConfigurations(partition, scanner, packageManagerOverlayInfos); packageManagerOverlayInfos, activeApexesPerPartition.getOrDefault(partition.type, Collections.emptyList())); if (partitionOverlays != null) { foundConfigFile = true; overlays.addAll(partitionOverlays); Loading @@ -147,7 +156,8 @@ public class OverlayConfig { // Filter out overlays not present in the partition. partitionOverlayInfos = new ArrayList<>(packageManagerOverlayInfos.values()); 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 @@ -294,16 +304,50 @@ public class OverlayConfig { private static Map<String, ParsedOverlayInfo> getOverlayPackageInfos( @NonNull PackageProvider packageManager) { final HashMap<String, ParsedOverlayInfo> overlays = new HashMap<>(); packageManager.forEachPackage((ParsingPackageRead p, Boolean isSystem) -> { packageManager.forEachPackage((ParsingPackageRead p, Boolean isSystem, @Nullable File preInstalledApexPath) -> { if (p.getOverlayTarget() != null && isSystem) { overlays.put(p.getPackageName(), new ParsedOverlayInfo(p.getPackageName(), p.getOverlayTarget(), p.getTargetSdkVersion(), p.isOverlayIsStatic(), p.getOverlayPriority(), new File(p.getBaseApkPath()))); p.getOverlayPriority(), 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 @@ -41,6 +41,7 @@ import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; /** Loading Loading @@ -195,14 +196,20 @@ final class OverlayConfigParser { @Nullable static ArrayList<ParsedConfiguration> getConfigurations( @NonNull OverlayPartition partition, @Nullable OverlayScanner scanner, @Nullable Map<String, ParsedOverlayInfo> packageManagerOverlayInfos) { if (partition.getOverlayFolder() == null) { return null; } @Nullable Map<String, ParsedOverlayInfo> packageManagerOverlayInfos, @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 @@ -54,23 +54,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 @@ -189,6 +204,6 @@ public class OverlayScanner { } return 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 @@ -297,6 +297,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 +50 −6 Original line number Diff line number Diff line Loading @@ -26,20 +26,25 @@ import android.util.ArrayMap; import android.util.IndentingPrintWriter; 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.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.BiConsumer; import java.util.function.Supplier; /** Loading Loading @@ -77,7 +82,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 @@ -119,6 +124,8 @@ public class OverlayConfig { p))); } ArrayMap<Integer, List<String>> activeApexesPerPartition = getActiveApexes(partitions); boolean foundConfigFile = false; final Map<String, ParsedOverlayInfo> packageManagerOverlayInfos = packageProvider == null ? null : getOverlayPackageInfos(packageProvider); Loading @@ -129,7 +136,9 @@ public class OverlayConfig { final OverlayScanner scanner = (scannerFactory == null) ? null : scannerFactory.get(); final ArrayList<ParsedConfiguration> partitionOverlays = OverlayConfigParser.getConfigurations(partition, scanner, packageManagerOverlayInfos); packageManagerOverlayInfos, activeApexesPerPartition.getOrDefault(partition.type, Collections.emptyList())); if (partitionOverlays != null) { foundConfigFile = true; overlays.addAll(partitionOverlays); Loading @@ -147,7 +156,8 @@ public class OverlayConfig { // Filter out overlays not present in the partition. partitionOverlayInfos = new ArrayList<>(packageManagerOverlayInfos.values()); 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 @@ -294,16 +304,50 @@ public class OverlayConfig { private static Map<String, ParsedOverlayInfo> getOverlayPackageInfos( @NonNull PackageProvider packageManager) { final HashMap<String, ParsedOverlayInfo> overlays = new HashMap<>(); packageManager.forEachPackage((ParsingPackageRead p, Boolean isSystem) -> { packageManager.forEachPackage((ParsingPackageRead p, Boolean isSystem, @Nullable File preInstalledApexPath) -> { if (p.getOverlayTarget() != null && isSystem) { overlays.put(p.getPackageName(), new ParsedOverlayInfo(p.getPackageName(), p.getOverlayTarget(), p.getTargetSdkVersion(), p.isOverlayIsStatic(), p.getOverlayPriority(), new File(p.getBaseApkPath()))); p.getOverlayPriority(), 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 @@ -41,6 +41,7 @@ import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; /** Loading Loading @@ -195,14 +196,20 @@ final class OverlayConfigParser { @Nullable static ArrayList<ParsedConfiguration> getConfigurations( @NonNull OverlayPartition partition, @Nullable OverlayScanner scanner, @Nullable Map<String, ParsedOverlayInfo> packageManagerOverlayInfos) { if (partition.getOverlayFolder() == null) { return null; } @Nullable Map<String, ParsedOverlayInfo> packageManagerOverlayInfos, @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 @@ -54,23 +54,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 @@ -189,6 +204,6 @@ public class OverlayScanner { } return 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