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

Commit 2b2ddee2 authored by Pedro Loureiro's avatar Pedro Loureiro Committed by Android (Google) Code Review
Browse files

Merge "Allow framework-res APK splits from Apexes"

parents 4a392f53 c6d1dec2
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -218,7 +218,7 @@ public class PackageParsingPerfTest {
            })

        override fun parseImpl(file: File) =
                parser.parsePackage(input.get()!!.reset(), file, 0).result
                parser.parsePackage(input.get()!!.reset(), file, 0, null).result
                        as ParsingPackageImpl
    }

+45 −13
Original line number Diff line number Diff line
@@ -78,6 +78,7 @@ public class ApkLiteParseUtils {
    public static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";
    private static final int PARSE_IS_SYSTEM_DIR = 1 << 4;
    private static final int PARSE_COLLECT_CERTIFICATES = 1 << 5;
    private static final int PARSE_FRAMEWORK_RES_SPLITS = 1 << 8;
    private static final String TAG_APPLICATION = "application";
    private static final String TAG_PACKAGE_VERIFIER = "package-verifier";
    private static final String TAG_PROFILEABLE = "profileable";
@@ -101,7 +102,7 @@ public class ApkLiteParseUtils {
    public static ParseResult<PackageLite> parsePackageLite(ParseInput input,
            File packageFile, int flags) {
        if (packageFile.isDirectory()) {
            return parseClusterPackageLite(input, packageFile, flags);
            return parseClusterPackageLite(input, packageFile, /* frameworkSplits= */ null, flags);
        } else {
            return parseMonolithicPackageLite(input, packageFile, flags);
        }
@@ -134,21 +135,44 @@ public class ApkLiteParseUtils {

    /**
     * Parse lightweight details about a directory of APKs.
     *
     * @param packageDirOrApk is the folder that contains split apks for a regular app or the
     *                        framework-res.apk for framwork-res splits (in which case the
     *                        splits come in the <code>frameworkSplits</code> parameter)
     */
    public static ParseResult<PackageLite> parseClusterPackageLite(ParseInput input,
            File packageDir, int flags) {
        final File[] files = packageDir.listFiles();
            File packageDirOrApk, List<File> frameworkSplits, int flags) {
        final File[] files;
        final boolean parsingFrameworkSplits = (flags & PARSE_FRAMEWORK_RES_SPLITS) != 0;
        if (parsingFrameworkSplits) {
            if (ArrayUtils.isEmpty(frameworkSplits)) {
                return input.error(PackageManager.INSTALL_PARSE_FAILED_NOT_APK,
                        "No packages found in split");
            }
            files = frameworkSplits.toArray(new File[frameworkSplits.size() + 1]);
            // we also want to process the base apk so add it to the array
            files[files.length - 1] = packageDirOrApk;
        } else {
            files = packageDirOrApk.listFiles();
            if (ArrayUtils.isEmpty(files)) {
                return input.error(PackageManager.INSTALL_PARSE_FAILED_NOT_APK,
                        "No packages found in split");
            }
            // Apk directory is directly nested under the current directory
            if (files.length == 1 && files[0].isDirectory()) {
            return parseClusterPackageLite(input, files[0], flags);
                return parseClusterPackageLite(input, files[0], frameworkSplits, flags);
            }
        }

        if (parsingFrameworkSplits) {
            // disable the flag for checking the certificates of the splits. We know they
            // won't match, but we rely on the mainline apex to be safe if it was installed
            flags = flags & ~PARSE_COLLECT_CERTIFICATES;
        }

        String packageName = null;
        int versionCode = 0;
        ApkLite baseApk = null;

        final ArrayMap<String, ApkLite> apks = new ArrayMap<>();
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parseApkLite");
@@ -161,6 +185,10 @@ public class ApkLiteParseUtils {
                    }

                    final ApkLite lite = result.getResult();
                    if (parsingFrameworkSplits && file == files[files.length - 1]) {
                        baseApk = lite;
                        break;
                    }
                    // Assert that all package names and version codes are
                    // consistent with the first one we encounter.
                    if (packageName == null) {
@@ -172,7 +200,8 @@ public class ApkLiteParseUtils {
                                    "Inconsistent package " + lite.getPackageName() + " in " + file
                                            + "; expected " + packageName);
                        }
                        if (versionCode != lite.getVersionCode()) {
                        // we allow version codes that do not match for framework splits
                        if (!parsingFrameworkSplits && versionCode != lite.getVersionCode()) {
                            return input.error(PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST,
                                    "Inconsistent version " + lite.getVersionCode() + " in " + file
                                            + "; expected " + versionCode);
@@ -187,12 +216,15 @@ public class ApkLiteParseUtils {
                    }
                }
            }
            // baseApk is set in the last iteration of the for each loop when we are parsing
            // frameworkRes splits or needs to be done now otherwise
            if (!parsingFrameworkSplits) {
                baseApk = apks.remove(null);
            }
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }

        final ApkLite baseApk = apks.remove(null);
        return composePackageLiteFromApks(input, packageDir, baseApk, apks);
        return composePackageLiteFromApks(input, packageDirOrApk, baseApk, apks);
    }

    /**
+40 −10
Original line number Diff line number Diff line
@@ -30,8 +30,10 @@ import static com.android.server.pm.PackageManagerService.SCAN_NO_DEX;
import static com.android.server.pm.PackageManagerService.SCAN_REQUIRE_KNOWN;
import static com.android.server.pm.PackageManagerService.SYSTEM_PARTITIONS;
import static com.android.server.pm.PackageManagerService.TAG;
import static com.android.server.pm.pkg.parsing.ParsingPackageUtils.PARSE_FRAMEWORK_RES_SPLITS;

import android.annotation.Nullable;
import android.content.pm.parsing.ApkLiteParseUtils;
import android.os.Environment;
import android.os.SystemClock;
import android.os.Trace;
@@ -91,6 +93,29 @@ final class InitAndSystemPackageHelper {
        mSystemScanFlags = scanFlags | SCAN_AS_SYSTEM;
    }

    private List<File> getFrameworkResApkSplitFiles() {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanFrameworkResApkSplits");
        try {
            final List<File> splits = new ArrayList<>();
            final List<ApexManager.ActiveApexInfo> activeApexInfos =
                    mPm.mApexManager.getActiveApexInfos();
            for (int i = 0; i < activeApexInfos.size(); i++) {
                ApexManager.ActiveApexInfo apexInfo = activeApexInfos.get(i);
                File splitsFolder = new File(apexInfo.apexDirectory, "etc/splits");
                if (splitsFolder.isDirectory()) {
                    for (File file : splitsFolder.listFiles()) {
                        if (ApkLiteParseUtils.isApkFile(file)) {
                            splits.add(file);
                        }
                    }
                }
            }
            return splits;
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
    }

    private List<ScanPartition> getSystemScanPartitions() {
        final List<ScanPartition> scanPartitions = new ArrayList<>();
        scanPartitions.addAll(mPm.mInjector.getSystemPartitions());
@@ -184,7 +209,8 @@ final class InitAndSystemPackageHelper {
        if (!mPm.isOnlyCoreApps()) {
            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
                    SystemClock.uptimeMillis());
            scanDirTracedLI(mPm.getAppInstallDir(), 0, mScanFlags | SCAN_REQUIRE_KNOWN, 0,
            scanDirTracedLI(mPm.getAppInstallDir(), /* frameworkSplits= */ null, 0,
                    mScanFlags | SCAN_REQUIRE_KNOWN, 0,
                    packageParser, executorService);

        }
@@ -247,12 +273,14 @@ final class InitAndSystemPackageHelper {
            if (partition.getOverlayFolder() == null) {
                continue;
            }
            scanDirTracedLI(partition.getOverlayFolder(), mSystemParseFlags,
                    mSystemScanFlags | partition.scanFlag, 0,
            scanDirTracedLI(partition.getOverlayFolder(), /* frameworkSplits= */ null,
                    mSystemParseFlags, mSystemScanFlags | partition.scanFlag, 0,
                    packageParser, executorService);
        }

        scanDirTracedLI(frameworkDir, mSystemParseFlags,
        List<File> frameworkSplits = getFrameworkResApkSplitFiles();
        scanDirTracedLI(frameworkDir, frameworkSplits,
                mSystemParseFlags | PARSE_FRAMEWORK_RES_SPLITS,
                mSystemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
                packageParser, executorService);
        if (!mPm.mPackages.containsKey("android")) {
@@ -263,12 +291,13 @@ final class InitAndSystemPackageHelper {
        for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
            final ScanPartition partition = mDirsToScanAsSystem.get(i);
            if (partition.getPrivAppFolder() != null) {
                scanDirTracedLI(partition.getPrivAppFolder(), mSystemParseFlags,
                scanDirTracedLI(partition.getPrivAppFolder(), /* frameworkSplits= */ null,
                        mSystemParseFlags,
                        mSystemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
                        packageParser, executorService);
            }
            scanDirTracedLI(partition.getAppFolder(), mSystemParseFlags,
                    mSystemScanFlags | partition.scanFlag, 0,
            scanDirTracedLI(partition.getAppFolder(), /* frameworkSplits= */ null,
                    mSystemParseFlags, mSystemScanFlags | partition.scanFlag, 0,
                    packageParser, executorService);
        }
    }
@@ -285,12 +314,13 @@ final class InitAndSystemPackageHelper {
    }

    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
    private void scanDirTracedLI(File scanDir, final int parseFlags, int scanFlags,
    private void scanDirTracedLI(File scanDir, List<File> frameworkSplits,
            final int parseFlags, int scanFlags,
            long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "scanDir [" + scanDir.getAbsolutePath() + "]");
        try {
            mInstallPackageHelper.installPackagesFromDir(scanDir, parseFlags, scanFlags,
                    currentTime, packageParser, executorService);
            mInstallPackageHelper.installPackagesFromDir(scanDir, frameworkSplits, parseFlags,
                    scanFlags, currentTime, packageParser, executorService);
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
+4 −3
Original line number Diff line number Diff line
@@ -3406,8 +3406,9 @@ final class InstallPackageHelper {
    }

    @GuardedBy({"mPm.mInstallLock", "mPm.mLock"})
    public void installPackagesFromDir(File scanDir, int parseFlags, int scanFlags,
            long currentTime, PackageParser2 packageParser, ExecutorService executorService) {
    public void installPackagesFromDir(File scanDir, List<File> frameworkSplits, int parseFlags,
            int scanFlags, long currentTime, PackageParser2 packageParser,
            ExecutorService executorService) {
        final File[] files = scanDir.listFiles();
        if (ArrayUtils.isEmpty(files)) {
            Log.d(TAG, "No files in app dir " + scanDir);
@@ -3419,7 +3420,7 @@ final class InstallPackageHelper {
                    + " flags=0x" + Integer.toHexString(parseFlags));
        }
        ParallelPackageParser parallelPackageParser =
                new ParallelPackageParser(packageParser, executorService);
                new ParallelPackageParser(packageParser, executorService, frameworkSplits);

        // Submit files for parsing in parallel
        int fileCount = 0;
+10 −1
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.pkg.ParsedPackage;

import java.io.File;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
@@ -54,9 +55,17 @@ class ParallelPackageParser {

    private final ExecutorService mExecutorService;

    private final List<File> mFrameworkSplits;

    ParallelPackageParser(PackageParser2 packageParser, ExecutorService executorService) {
        this(packageParser, executorService, /* frameworkSplits= */ null);
    }

    ParallelPackageParser(PackageParser2 packageParser, ExecutorService executorService,
            List<File> frameworkSplits) {
        mPackageParser = packageParser;
        mExecutorService = executorService;
        mFrameworkSplits = frameworkSplits;
    }

    static class ParseResult {
@@ -125,6 +134,6 @@ class ParallelPackageParser {
    @VisibleForTesting
    protected ParsedPackage parsePackage(File scanFile, int parseFlags)
            throws PackageManagerException {
        return mPackageParser.parsePackage(scanFile, parseFlags, true);
        return mPackageParser.parsePackage(scanFile, parseFlags, true, mFrameworkSplits);
    }
}
Loading