summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2021-10-26 21:58:13 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2021-10-26 21:58:13 +0000
commitde3baffb292a5112fa1e6e559cf76bb5305fe2ef (patch)
tree488469cf816abf8cb11b6fde359190b15ede3722
parent6f1b7122f317b0bee46b367218fb5cb571ccddf6 (diff)
parent653a1c1a287b25535b23dbec1b023974a4416a10 (diff)
downloadbase-de3baffb292a5112fa1e6e559cf76bb5305fe2ef.tar.gz
Merge "Fix RRO loading from inside APEXes."
-rw-r--r--Android.bp1
-rw-r--r--core/java/com/android/internal/content/om/OverlayConfig.java55
-rw-r--r--core/java/com/android/internal/content/om/OverlayConfigParser.java17
-rw-r--r--core/java/com/android/internal/content/om/OverlayScanner.java23
-rw-r--r--core/jni/fd_utils.cpp8
-rw-r--r--core/tests/coretests/src/com/android/internal/content/res/OverlayConfigIterationRule.java11
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java9
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<>();