diff options
author | Treehugger Robot <treehugger-gerrit@google.com> | 2021-10-26 21:58:13 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2021-10-26 21:58:13 +0000 |
commit | de3baffb292a5112fa1e6e559cf76bb5305fe2ef (patch) | |
tree | 488469cf816abf8cb11b6fde359190b15ede3722 | |
parent | 6f1b7122f317b0bee46b367218fb5cb571ccddf6 (diff) | |
parent | 653a1c1a287b25535b23dbec1b023974a4416a10 (diff) | |
download | base-de3baffb292a5112fa1e6e559cf76bb5305fe2ef.tar.gz |
Merge "Fix RRO loading from inside APEXes."
7 files changed, 103 insertions, 21 deletions
diff --git a/Android.bp b/Android.bp index d976b9172602..00b419897f34 100644 --- a/Android.bp +++ b/Android.bp @@ -294,6 +294,7 @@ java_defaults { srcs: [ ":framework-non-updatable-sources", "core/java/**/*.logtags", + ":apex-info-list", ], aidl: { generate_get_transaction_name: true, diff --git a/core/java/com/android/internal/content/om/OverlayConfig.java b/core/java/com/android/internal/content/om/OverlayConfig.java index 3f3c9bdbe5f5..7c391186c839 100644 --- a/core/java/com/android/internal/content/om/OverlayConfig.java +++ b/core/java/com/android/internal/content/om/OverlayConfig.java @@ -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; /** @@ -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) -> { @@ -115,6 +120,8 @@ public class OverlayConfig { p))); } + ArrayMap<Integer, List<String>> activeApexesPerPartition = getActiveApexes(partitions); + boolean foundConfigFile = false; ArrayList<ParsedOverlayInfo> packageManagerOverlayInfos = null; @@ -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); @@ -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); } } @@ -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 { diff --git a/core/java/com/android/internal/content/om/OverlayConfigParser.java b/core/java/com/android/internal/content/om/OverlayConfigParser.java index a86e5950c2f6..d48c2e764625 100644 --- a/core/java/com/android/internal/content/om/OverlayConfigParser.java +++ b/core/java/com/android/internal/content/om/OverlayConfigParser.java @@ -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, @@ -192,13 +193,19 @@ 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 (scanner != null) { - scanner.scanDir(partition.getOverlayFolder()); + if (partition.getOverlayFolder() == null) { + return null; } final File configFile = new File(partition.getOverlayFolder(), CONFIG_DEFAULT_FILENAME); diff --git a/core/java/com/android/internal/content/om/OverlayScanner.java b/core/java/com/android/internal/content/om/OverlayScanner.java index 6b5cb8d9b850..138d1ce91719 100644 --- a/core/java/com/android/internal/content/om/OverlayScanner.java +++ b/core/java/com/android/internal/content/om/OverlayScanner.java @@ -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; } } @@ -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); } } diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index 6f5cc5314d0b..40f6e4f63cd7 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -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) && diff --git a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java index c50c818be716..e2c40d8b699b 100644 --- a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java +++ b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java @@ -28,6 +28,7 @@ import android.util.ArrayMap; import com.android.internal.content.om.OverlayConfig.PackageProvider; import com.android.internal.content.om.OverlayScanner; import com.android.internal.content.om.OverlayScanner.ParsedOverlayInfo; +import com.android.internal.util.function.TriConsumer; import org.junit.Assert; import org.junit.rules.TestRule; @@ -39,7 +40,6 @@ import org.mockito.invocation.InvocationOnMock; import java.io.File; import java.io.IOException; import java.util.Map; -import java.util.function.BiConsumer; import java.util.function.Supplier; /** @@ -73,7 +73,7 @@ public class OverlayConfigIterationRule implements TestRule { final File canonicalPath = new File(path.getCanonicalPath()); mOverlayStubResults.put(canonicalPath, new ParsedOverlayInfo( packageName, targetPackage, targetSdkVersion, isStatic, priority, - canonicalPath)); + canonicalPath, null)); } catch (IOException e) { Assert.fail("Failed to add overlay " + e); } @@ -135,8 +135,8 @@ public class OverlayConfigIterationRule implements TestRule { mIteration = Iteration.SYSTEM_SERVER; doAnswer((InvocationOnMock invocation) -> { final Object[] args = invocation.getArguments(); - final BiConsumer<ParsingPackageRead, Boolean> f = - (BiConsumer<ParsingPackageRead, Boolean>) args[0]; + final TriConsumer<ParsingPackageRead, Boolean, File> f = + (TriConsumer<ParsingPackageRead, Boolean, File>) args[0]; for (Map.Entry<File, ParsedOverlayInfo> overlay : mOverlayStubResults.entrySet()) { final ParsingPackageRead a = Mockito.mock(ParsingPackageRead.class); @@ -147,7 +147,8 @@ public class OverlayConfigIterationRule implements TestRule { when(a.isOverlayIsStatic()).thenReturn(info.isStatic); when(a.getOverlayPriority()).thenReturn(info.priority); when(a.getBaseApkPath()).thenReturn(info.path.getPath()); - f.accept(a, !info.path.getPath().contains("data/overlay")); + f.accept(a, !info.path.getPath().contains("data/overlay"), + /*preInstalledApexPath=*/null); } return null; }).when(mPkgProvider).forEachPackage(any()); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index f6acad0194c1..827dfc0caa16 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -7337,9 +7337,16 @@ public class PackageManagerService extends IPackageManager.Stub // Parse overlay configuration files to set default enable state, mutability, and // priority of system overlays. + final ArrayMap<String, File> apkInApexPreInstalledPaths = new ArrayMap<>(); + for (ApexManager.ActiveApexInfo apexInfo : mApexManager.getActiveApexInfos()) { + for (String packageName : mApexManager.getApksInApex(apexInfo.apexModuleName)) { + apkInApexPreInstalledPaths.put(packageName, apexInfo.preInstalledApexPath); + } + } mOverlayConfig = OverlayConfig.initializeSystemInstance( consumer -> mPmInternal.forEachPackage( - pkg -> consumer.accept(pkg, pkg.isSystem()))); + pkg -> consumer.accept(pkg, pkg.isSystem(), + apkInApexPreInstalledPaths.get(pkg.getPackageName())))); // Prune any system packages that no longer exist. final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>(); |