Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 28382069 authored by Daniel Norman's avatar Daniel Norman Committed by Android (Google) Code Review
Browse files

Merge "Fix RRO loading from inside APEXes."

parents 22f575a0 66ebced1
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -297,6 +297,7 @@ java_defaults {
    srcs: [
    srcs: [
        ":framework-non-updatable-sources",
        ":framework-non-updatable-sources",
        "core/java/**/*.logtags",
        "core/java/**/*.logtags",
        ":apex-info-list",
    ],
    ],
    aidl: {
    aidl: {
        generate_get_transaction_name: true,
        generate_get_transaction_name: true,
+50 −6
Original line number Original line Diff line number Diff line
@@ -26,20 +26,25 @@ import android.util.ArrayMap;
import android.util.IndentingPrintWriter;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Log;


import com.android.apex.ApexInfo;
import com.android.apex.XmlParser;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.om.OverlayConfigParser.OverlayPartition;
import com.android.internal.content.om.OverlayConfigParser.OverlayPartition;
import com.android.internal.content.om.OverlayConfigParser.ParsedConfiguration;
import com.android.internal.content.om.OverlayConfigParser.ParsedConfiguration;
import com.android.internal.content.om.OverlayScanner.ParsedOverlayInfo;
import com.android.internal.content.om.OverlayScanner.ParsedOverlayInfo;
import com.android.internal.util.Preconditions;
import com.android.internal.util.Preconditions;
import com.android.internal.util.function.TriConsumer;


import java.io.File;
import java.io.File;
import java.io.FileInputStream;
import java.io.PrintWriter;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Supplier;
import java.util.function.Supplier;


/**
/**
@@ -77,7 +82,7 @@ public class OverlayConfig {
    public interface PackageProvider {
    public interface PackageProvider {


        /** Performs the given action for each package. */
        /** 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) -> {
    private static final Comparator<ParsedConfiguration> sStaticOverlayComparator = (c1, c2) -> {
@@ -119,6 +124,8 @@ public class OverlayConfig {
                            p)));
                            p)));
        }
        }


        ArrayMap<Integer, List<String>> activeApexesPerPartition = getActiveApexes(partitions);

        boolean foundConfigFile = false;
        boolean foundConfigFile = false;
        final Map<String, ParsedOverlayInfo> packageManagerOverlayInfos =
        final Map<String, ParsedOverlayInfo> packageManagerOverlayInfos =
                packageProvider == null ? null : getOverlayPackageInfos(packageProvider);
                packageProvider == null ? null : getOverlayPackageInfos(packageProvider);
@@ -129,7 +136,9 @@ public class OverlayConfig {
            final OverlayScanner scanner = (scannerFactory == null) ? null : scannerFactory.get();
            final OverlayScanner scanner = (scannerFactory == null) ? null : scannerFactory.get();
            final ArrayList<ParsedConfiguration> partitionOverlays =
            final ArrayList<ParsedConfiguration> partitionOverlays =
                    OverlayConfigParser.getConfigurations(partition, scanner,
                    OverlayConfigParser.getConfigurations(partition, scanner,
                            packageManagerOverlayInfos);
                            packageManagerOverlayInfos,
                            activeApexesPerPartition.getOrDefault(partition.type,
                                    Collections.emptyList()));
            if (partitionOverlays != null) {
            if (partitionOverlays != null) {
                foundConfigFile = true;
                foundConfigFile = true;
                overlays.addAll(partitionOverlays);
                overlays.addAll(partitionOverlays);
@@ -147,7 +156,8 @@ public class OverlayConfig {
                // Filter out overlays not present in the partition.
                // Filter out overlays not present in the partition.
                partitionOverlayInfos = new ArrayList<>(packageManagerOverlayInfos.values());
                partitionOverlayInfos = new ArrayList<>(packageManagerOverlayInfos.values());
                for (int j = partitionOverlayInfos.size() - 1; j >= 0; j--) {
                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);
                        partitionOverlayInfos.remove(j);
                    }
                    }
                }
                }
@@ -294,16 +304,50 @@ public class OverlayConfig {
    private static Map<String, ParsedOverlayInfo> getOverlayPackageInfos(
    private static Map<String, ParsedOverlayInfo> getOverlayPackageInfos(
            @NonNull PackageProvider packageManager) {
            @NonNull PackageProvider packageManager) {
        final HashMap<String, ParsedOverlayInfo> overlays = new HashMap<>();
        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) {
            if (p.getOverlayTarget() != null && isSystem) {
                overlays.put(p.getPackageName(), new ParsedOverlayInfo(p.getPackageName(),
                overlays.put(p.getPackageName(), new ParsedOverlayInfo(p.getPackageName(),
                        p.getOverlayTarget(), p.getTargetSdkVersion(), p.isOverlayIsStatic(),
                        p.getOverlayTarget(), p.getTargetSdkVersion(), p.isOverlayIsStatic(),
                        p.getOverlayPriority(), new File(p.getBaseApkPath())));
                        p.getOverlayPriority(), new File(p.getBaseApkPath()),
                        preInstalledApexPath));
            }
            }
        });
        });
        return overlays;
        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. */
    /** Represents a single call to idmap create-multiple. */
    @VisibleForTesting
    @VisibleForTesting
    public static class IdmapInvocation {
    public static class IdmapInvocation {
+12 −5
Original line number Original line Diff line number Diff line
@@ -41,6 +41,7 @@ import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map;


/**
/**
@@ -195,14 +196,20 @@ final class OverlayConfigParser {
    @Nullable
    @Nullable
    static ArrayList<ParsedConfiguration> getConfigurations(
    static ArrayList<ParsedConfiguration> getConfigurations(
            @NonNull OverlayPartition partition, @Nullable OverlayScanner scanner,
            @NonNull OverlayPartition partition, @Nullable OverlayScanner scanner,
            @Nullable Map<String, ParsedOverlayInfo> packageManagerOverlayInfos) {
            @Nullable Map<String, ParsedOverlayInfo> packageManagerOverlayInfos,
        if (partition.getOverlayFolder() == null) {
            @NonNull List<String> activeApexes) {
            return null;
        }

        if (scanner != null) {
        if (scanner != null) {
            if (partition.getOverlayFolder() != null) {
                scanner.scanDir(partition.getOverlayFolder());
                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);
        final File configFile = new File(partition.getOverlayFolder(), CONFIG_DEFAULT_FILENAME);
        if (!configFile.exists()) {
        if (!configFile.exists()) {
+19 −4
Original line number Original line Diff line number Diff line
@@ -54,23 +54,38 @@ public class OverlayScanner {
        public final boolean isStatic;
        public final boolean isStatic;
        public final int priority;
        public final int priority;
        public final File path;
        public final File path;
        @Nullable public final File preInstalledApexPath;


        public ParsedOverlayInfo(String packageName, String targetPackageName,
        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.packageName = packageName;
            this.targetPackageName = targetPackageName;
            this.targetPackageName = targetPackageName;
            this.targetSdkVersion = targetSdkVersion;
            this.targetSdkVersion = targetSdkVersion;
            this.isStatic = isStatic;
            this.isStatic = isStatic;
            this.priority = priority;
            this.priority = priority;
            this.path = path;
            this.path = path;
            this.preInstalledApexPath = preInstalledApexPath;
        }
        }


        @Override
        @Override
        public String toString() {
        public String toString() {
            return getClass().getSimpleName() + String.format("{packageName=%s"
            return getClass().getSimpleName() + String.format("{packageName=%s"
                            + ", targetPackageName=%s, targetSdkVersion=%s, isStatic=%s"
                            + ", targetPackageName=%s, targetSdkVersion=%s, isStatic=%s"
                            + ", priority=%s, path=%s}",
                            + ", priority=%s, path=%s, preInstalledApexPath=%s}",
                    packageName, targetPackageName, targetSdkVersion, isStatic, priority, path);
                    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;
        }
        }
    }
    }


@@ -189,6 +204,6 @@ public class OverlayScanner {
        }
        }
        return new ParsedOverlayInfo(apkLite.getPackageName(), apkLite.getTargetPackageName(),
        return new ParsedOverlayInfo(apkLite.getPackageName(), apkLite.getTargetPackageName(),
                apkLite.getTargetSdkVersion(), apkLite.isOverlayIsStatic(),
                apkLite.getTargetSdkVersion(), apkLite.isOverlayIsStatic(),
                apkLite.getOverlayPriority(), new File(apkLite.getPath()));
                apkLite.getOverlayPriority(), new File(apkLite.getPath()), null);
    }
    }
}
}
+8 −0
Original line number Original line Diff line number Diff line
@@ -138,6 +138,14 @@ bool FileDescriptorAllowlist::IsAllowed(const std::string& path) const {
        return true;
        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* kOverlayIdmapPrefix = "/data/resource-cache/";
    static const char* kOverlayIdmapSuffix = ".apk@idmap";
    static const char* kOverlayIdmapSuffix = ".apk@idmap";
    if (android::base::StartsWith(path, kOverlayIdmapPrefix) &&
    if (android::base::StartsWith(path, kOverlayIdmapPrefix) &&
Loading