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

Commit 275e085d authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Stronger PackageParser contract, more split work.

Require that method callers always provide relevant paths, instead of
relying on constructor.  Move DisplayMetrics to be an overall parser
parameter, and move PARSE_TRUSTED_OVERLAY to flags.

Parse split APKs and apply deterministic ordering based on split
names.  Assert consistent package name and version code across all
split APKs in a package, and enforce unique split names and required
base APK.

Collect certificates for split APKs, enforcing they're all signed
consistently.  Better flow control and resource cleanup when
collecting certs.  Refactor validation code so it's easier to reason
about.  Cleaner maintenance of read buffer when draining stream
contents.

Change-Id: I8bc8c62095fbb933227b9e76ad8771f4b1246fe8
parent b593539f
Loading
Loading
Loading
Loading
+4 −7
Original line number Diff line number Diff line
@@ -2870,15 +2870,12 @@ public abstract class PackageManager {
     *
     */
    public PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags) {
        PackageParser packageParser = new PackageParser(archiveFilePath);
        DisplayMetrics metrics = new DisplayMetrics();
        metrics.setToDefaults();
        final File sourceFile = new File(archiveFilePath);
        final PackageParser parser = new PackageParser();
        final File apkFile = new File(archiveFilePath);
        try {
            PackageParser.Package pkg = packageParser.parseMonolithicPackage(sourceFile, metrics,
                    0);
            PackageParser.Package pkg = parser.parseMonolithicPackage(apkFile, 0);
            if ((flags & GET_SIGNATURES) != 0) {
                packageParser.collectCertificates(pkg, 0);
                parser.collectCertificates(pkg, 0);
            }
            PackageUserState state = new PackageUserState();
            return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);
+320 −276

File changed.

Preview size limit exceeded, changes collapsed.

+2 −4
Original line number Diff line number Diff line
@@ -305,11 +305,9 @@ public class PackageManagerTests extends AndroidTestCase {

    private PackageParser.Package parsePackage(Uri packageURI) throws PackageParserException {
        final String archiveFilePath = packageURI.getPath();
        PackageParser packageParser = new PackageParser(archiveFilePath);
        PackageParser packageParser = new PackageParser();
        File sourceFile = new File(archiveFilePath);
        DisplayMetrics metrics = new DisplayMetrics();
        metrics.setToDefaults();
        PackageParser.Package pkg = packageParser.parseMonolithicPackage(sourceFile, metrics, 0);
        PackageParser.Package pkg = packageParser.parseMonolithicPackage(sourceFile, 0);
        packageParser = null;
        return pkg;
    }
+7 −6
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageInfoLite;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageParserException;
import android.content.res.ObbInfo;
import android.content.res.ObbScanner;
import android.net.Uri;
@@ -157,6 +158,7 @@ public class DefaultContainerService extends IntentService {
         * @return Returns PackageInfoLite object containing
         * the package info and recommended app location.
         */
        @Override
        public PackageInfoLite getMinimalPackageInfo(final String packagePath, int flags,
                long threshold, String abiOverride) {
            PackageInfoLite ret = new PackageInfoLite();
@@ -167,14 +169,13 @@ public class DefaultContainerService extends IntentService {
                return ret;
            }

            DisplayMetrics metrics = new DisplayMetrics();
            metrics.setToDefaults();

            PackageParser.ApkLite pkg = PackageParser.parseApkLite(packagePath, 0);
            if (pkg == null) {
            final File apkFile = new File(packagePath);
            final PackageParser.ApkLite pkg;
            try {
                pkg = PackageParser.parseApkLite(apkFile, 0);
            } catch (PackageParserException e) {
                Slog.w(TAG, "Failed to parse package");

                final File apkFile = new File(packagePath);
                if (!apkFile.exists()) {
                    ret.recommendedInstallLocation = PackageHelper.RECOMMEND_FAILED_INVALID_URI;
                } else {
+12 −12
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import android.content.pm.PackageInstallerParams;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.PackageParser.ApkLite;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.Signature;
import android.os.Build;
import android.os.Bundle;
@@ -50,14 +51,10 @@ import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.Preconditions;

import libcore.io.IoUtils;
import libcore.io.Libcore;
import libcore.io.Streams;

import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;

@@ -297,11 +294,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {

        // Verify that all staged packages are internally consistent
        for (File file : files) {
            final ApkLite info = PackageParser.parseApkLite(file.getAbsolutePath(),
                    PackageParser.PARSE_GET_SIGNATURES);
            if (info == null) {
            final ApkLite info;
            try {
                info = PackageParser.parseApkLite(file, PackageParser.PARSE_GET_SIGNATURES);
            } catch (PackageParserException e) {
                throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
                        "Failed to parse " + file);
                        "Failed to parse " + file + ": " + e);
            }

            if (!seenSplits.add(info.splitName)) {
@@ -356,11 +354,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
                        "Missing existing base package for " + mPackageName);
            }

            final ApkLite info = PackageParser.parseApkLite(app.sourceDir,
            final ApkLite info;
            try {
                info = PackageParser.parseApkLite(new File(app.sourceDir),
                        PackageParser.PARSE_GET_SIGNATURES);
            if (info == null) {
            } catch (PackageParserException e) {
                throw new InstallFailedException(INSTALL_FAILED_INVALID_APK,
                        "Failed to parse existing base " + app.sourceDir);
                        "Failed to parse existing base " + app.sourceDir + ": " + e);
            }

            assertPackageConsistent("Existing base", info.packageName, info.versionCode,
Loading