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

Commit 57dcf5b1 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Slow progress towards APK clusters.

Differentiate between "split APKs" and "cluster packages".  A cluster
package is a directory containing zero or more APKs (base+splits),
and a monolithic package is a single APK (base).

PackageSetting will use the directory name as its codePath, so track
the baseCodePath separately.  Clarify documentation in several
places.

Require that all installers provide file:// URIs through existing
hidden APIs; PackageInstaller hasn't been able to read content://
URIs for a long time.

Bug: 14975160
Change-Id: I1c6fed1b55205c2474b09871161a98a26669d22e
parent 6ee242a5
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -413,6 +413,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
    /**
     * Full path to the base APK for this application.
     */
    // TODO: verify that nobody is doing codePath comparisons against this
    public String sourceDir;

    /**
+38 −29
Original line number Diff line number Diff line
@@ -279,11 +279,11 @@ public class PackageParser {
        mMetrics = metrics;
    }

    private static final boolean isPackageFilename(File file) {
    public static final boolean isPackageFilename(File file) {
        return isPackageFilename(file.getName());
    }

    private static final boolean isPackageFilename(String name) {
    public static final boolean isPackageFilename(String name) {
        return name.endsWith(".apk");
    }

@@ -552,7 +552,7 @@ public class PackageParser {
     * Note that this <em>does not</em> perform signature verification; that
     * must be done separately in {@link #collectCertificates(Package, int)}.
     */
    public Package parseSplitPackage(File apkDir, int flags) throws PackageParserException {
    public Package parseClusterPackage(File apkDir, int flags) throws PackageParserException {
        final File[] files = apkDir.listFiles();
        if (ArrayUtils.isEmpty(files)) {
            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
@@ -600,27 +600,23 @@ public class PackageParser {
                    "Missing base APK in " + apkDir);
        }

        // Always apply deterministic ordering based on splitName
        final int size = apks.size();

        final String[] splitNames = apks.keySet().toArray(new String[size]);
        Arrays.sort(splitNames, sSplitNameComparator);

        final File[] splitFiles = new File[size];
        for (int i = 0; i < size; i++) {
            splitFiles[i] = apks.get(splitNames[i]);
        }

        final Package pkg = parseBaseApk(baseFile, flags);
        if (pkg == null) {
            throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
                    "Failed to parse base APK: " + baseFile);
        }

        for (File splitFile : splitFiles) {
            parseSplitApk(pkg, splitFile, flags);
        // Always apply deterministic ordering based on splitName
        final int size = apks.size();
        final String[] splitNames = apks.keySet().toArray(new String[size]);
        Arrays.sort(splitNames, sSplitNameComparator);

        for (String splitName : splitNames) {
            final File splitFile = apks.get(splitName);
            parseSplitApk(pkg, splitFile, splitName, flags);
        }

        pkg.codePath = apkDir.getAbsolutePath();
        return pkg;
    }

@@ -632,11 +628,12 @@ public class PackageParser {
     */
    public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
        final Package pkg = parseBaseApk(apkFile, flags);
        if (pkg != null) {
            return pkg;
        } else {
        if (pkg == null) {
            throw new PackageParserException(mParseError, "Failed to parse " + apkFile);
        }

        pkg.codePath = apkFile.getAbsolutePath();
        return pkg;
    }

    private Package parseBaseApk(File apkFile, int flags) {
@@ -723,19 +720,22 @@ public class PackageParser {
        parser.close();
        assmgr.close();

        pkg.codePath = apkPath;
        pkg.baseCodePath = apkPath;
        pkg.mSignatures = null;

        return pkg;
    }

    private void parseSplitApk(Package pkg, File apkFile, int flags) throws PackageParserException {
        final String apkPath = apkFile.getAbsolutePath();
    private void parseSplitApk(Package pkg, File apkFile, String splitName, int flags)
            throws PackageParserException {
        final String splitCodePath = apkFile.getAbsolutePath();
        mArchiveSourcePath = apkFile.getAbsolutePath();

        // TODO: expand split APK parsing
        // TODO: extract splitName during parse
        pkg.splitNames = ArrayUtils.appendElement(String.class, pkg.splitNames, splitName);
        pkg.splitCodePaths = ArrayUtils.appendElement(String.class, pkg.splitCodePaths,
                apkFile.getAbsolutePath());
                splitCodePath);
    }

    /**
@@ -748,7 +748,7 @@ public class PackageParser {

        // TODO: extend to gather digest for split APKs
        try {
            final StrictJarFile jarFile = new StrictJarFile(pkg.codePath);
            final StrictJarFile jarFile = new StrictJarFile(pkg.baseCodePath);
            try {
                final ZipEntry je = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
                if (je != null) {
@@ -773,7 +773,7 @@ public class PackageParser {
        pkg.mSignatures = null;
        pkg.mSigningKeys = null;

        collectCertificates(pkg, new File(pkg.codePath), flags);
        collectCertificates(pkg, new File(pkg.baseCodePath), flags);

        if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
            for (String splitCodePath : pkg.splitCodePaths) {
@@ -3692,12 +3692,21 @@ public class PackageParser {
    public final static class Package {

        public String packageName;
        /** Names of any split APKs, ordered by parsed splitName */
        public String[] splitNames;

        // TODO: work towards making these paths invariant

        /** Base APK */
        /**
         * Path where this package was found on disk. For monolithic packages
         * this is path to single base APK file; for cluster packages this is
         * path to the cluster directory.
         */
        public String codePath;
        /** Split APKs, ordered by parsed splitName */

        /** Path of base APK */
        public String baseCodePath;
        /** Paths of any split APKs, ordered by parsed splitName */
        public String[] splitCodePaths;

        // For now we only support one application per package.
@@ -3816,9 +3825,9 @@ public class PackageParser {
            applicationInfo.uid = -1;
        }

        public Collection<String> getAllCodePaths() {
        public List<String> getAllCodePaths() {
            ArrayList<String> paths = new ArrayList<>();
            paths.add(codePath);
            paths.add(baseCodePath);
            if (!ArrayUtils.isEmpty(splitCodePaths)) {
                Collections.addAll(paths, splitCodePaths);
            }
+24 −3
Original line number Diff line number Diff line
@@ -384,16 +384,18 @@ public class FileUtils {
        return filePath.startsWith(dirPath);
    }

    public static void deleteContents(File dir) {
    public static boolean deleteContents(File dir) {
        File[] files = dir.listFiles();
        boolean success = true;
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    deleteContents(file);
                    success &= deleteContents(file);
                }
                file.delete();
                success &= file.delete();
            }
        }
        return success;
    }

    /**
@@ -411,4 +413,23 @@ public class FileUtils {
        }
        return true;
    }

    public static String rewriteAfterRename(File beforeDir, File afterDir, String path) {
        final File result = rewriteAfterRename(beforeDir, afterDir, new File(path));
        return (result != null) ? result.getAbsolutePath() : null;
    }

    /**
     * Given a path under the "before" directory, rewrite it to live under the
     * "after" directory. For example, {@code /before/foo/bar.txt} would become
     * {@code /after/foo/bar.txt}.
     */
    public static File rewriteAfterRename(File beforeDir, File afterDir, File file) {
        if (contains(beforeDir, file)) {
            final String splice = file.getAbsolutePath().substring(
                    beforeDir.getAbsolutePath().length());
            return new File(afterDir, splice);
        }
        return null;
    }
}
+19 −0
Original line number Diff line number Diff line
@@ -171,4 +171,23 @@ public class SELinux {
            return false;
        }
    }

    /**
     * Recursively restores all files under the given path to their default
     * SELinux security context. If the system is not compiled with SELinux,
     * then {@code true} is automatically returned. If SELinux is compiled in,
     * but disabled, then {@code true} is returned.
     *
     * @return a boolean indicating whether the relabeling succeeded.
     */
    public static boolean restoreconTree(File dir) {
        final File[] files = dir.listFiles();
        boolean success = true;
        if (files != null) {
            for (File file : files) {
                success &= restorecon(file);
            }
        }
        return success;
    }
}
+12 −14
Original line number Diff line number Diff line
@@ -16,27 +16,25 @@

package com.android.internal.app;

import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.content.pm.ContainerEncryptionParams;
import android.content.pm.PackageInfoLite;
import android.content.res.ObbInfo;

interface IMediaContainerService {
    String copyResourceToContainer(in Uri packageURI, String containerId, String key,
    String copyResourceToContainer(String packagePath, String containerId, String key,
            String resFileName, String publicResFileName, boolean isExternal,
            boolean isForwardLocked, in String abiOverride);
    int copyResource(in Uri packageURI, in ContainerEncryptionParams encryptionParams,
            boolean isForwardLocked, String abiOverride);
    int copyResource(String packagePath, in ContainerEncryptionParams encryptionParams,
            in ParcelFileDescriptor outStream);
    PackageInfoLite getMinimalPackageInfo(in String packagePath, in int flags, in long threshold,
            in String abiOverride);
    boolean checkInternalFreeStorage(in Uri fileUri, boolean isForwardLocked, in long threshold);
    boolean checkExternalFreeStorage(in Uri fileUri, boolean isForwardLocked, in String abiOverride);
    ObbInfo getObbInfo(in String filename);
    long calculateDirectorySize(in String directory);
    PackageInfoLite getMinimalPackageInfo(String packagePath, int flags, long threshold,
            String abiOverride);
    boolean checkInternalFreeStorage(String packagePath, boolean isForwardLocked, long threshold);
    boolean checkExternalFreeStorage(String packagePath, boolean isForwardLocked, String abiOverride);
    ObbInfo getObbInfo(String filename);
    long calculateDirectorySize(String directory);
    /** Return file system stats: [0] is total bytes, [1] is available bytes */
    long[] getFileSystemStats(in String path);
    void clearDirectory(in String directory);
    long calculateInstalledSize(in String packagePath, boolean isForwardLocked,
            in String abiOverride);
    long[] getFileSystemStats(String path);
    void clearDirectory(String directory);
    long calculateInstalledSize(String packagePath, boolean isForwardLocked, String abiOverride);
}
Loading