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

Commit 3eb63dc3 authored by Narayan Kamath's avatar Narayan Kamath Committed by Android (Google) Code Review
Browse files

Merge "Move linking and directory creation logic to installd." into mnc-dev

parents 3c300f0d e845a1ef
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -454,6 +454,18 @@ public final class Installer extends SystemService {
        return mInstaller.execute(builder.toString());
    }


    public int linkFile(String relativePath, String fromBase, String toBase) {
        StringBuilder builder = new StringBuilder("linkfile");
        builder.append(' ');
        builder.append(relativePath);
        builder.append(' ');
        builder.append(fromBase);
        builder.append(' ');
        builder.append(toBase);
        return mInstaller.execute(builder.toString());
    }

    /**
     * Returns true iff. {@code instructionSet} is a valid instruction set.
     */
+44 −66
Original line number Diff line number Diff line
@@ -166,6 +166,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    @GuardedBy("mLock")
    private final List<File> mResolvedInheritedFiles = new ArrayList<>();
    @GuardedBy("mLock")
    private final List<String> mResolvedInstructionSets = new ArrayList<>();
    @GuardedBy("mLock")
    private File mInheritedFilesBase;

    private final Handler.Callback mHandlerCallback = new Handler.Callback() {
@@ -521,7 +523,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
                }

                if (isLinkPossible(fromFiles, toDir)) {
                    createDirsAndLinkFiles(fromFiles, toDir, mInheritedFilesBase);
                    if (!mResolvedInstructionSets.isEmpty()) {
                        final File oatDir = new File(toDir, "oat");
                        createOatDirs(mResolvedInstructionSets, oatDir);
                    }
                    linkFiles(fromFiles, toDir, mInheritedFilesBase);
                } else {
                    // TODO: this should delegate to DCS so the system process
                    // avoids holding open FDs into containers.
@@ -706,10 +712,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
            final File oatDir = new File(packageInstallDir, "oat");
            if (oatDir.exists()) {
                final File[] archSubdirs = oatDir.listFiles();
                // Only add "oatDir" if it contains arch specific subdirs.

                // Keep track of all instruction sets we've seen compiled output for.
                // If we're linking (and not copying) inherited files, we can recreate the
                // instruction set hierarchy and link compiled output.
                if (archSubdirs != null && archSubdirs.length > 0) {
                    mResolvedInheritedFiles.add(oatDir);
                }
                    final String[] instructionSets = InstructionSets.getAllDexCodeInstructionSets();
                    for (File archSubDir : archSubdirs) {
                        // Skip any directory that isn't an ISA subdir.
@@ -717,15 +724,16 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
                            continue;
                        }

                        mResolvedInstructionSets.add(archSubDir.getName());
                        List<File> oatFiles = Arrays.asList(archSubDir.listFiles());
                        if (!oatFiles.isEmpty()) {
                        mResolvedInheritedFiles.add(archSubDir);
                            mResolvedInheritedFiles.addAll(oatFiles);
                        }
                    }
                }
            }
        }
    }

    private void assertApkConsistent(String tag, ApkLite apk) throws PackageManagerException {
        if (!mPackageName.equals(apk.packageName)) {
@@ -802,71 +810,41 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
        return true;
    }

    /**
     * Reparents the path of {@code file} from {@code oldBase} to {@code newBase}. {@code file}
     * must necessarily be a subpath of {@code oldBase}. It is an error for {@code file} to have
     * relative path components such as {@code "."} or {@code ".."}. For example, for we will
     * reparent {@code /foo/bar/baz} to {@code /foo2/bar/baz} if {@code oldBase} was {@code /foo}
     * and {@code newBase} was {@code /foo2}.
     */
    private static File reparentPath(File file, File oldBase, File newBase) throws IOException {
        final String oldBaseStr = oldBase.getAbsolutePath();
    private static String getRelativePath(File file, File base) throws IOException {
        final String pathStr = file.getAbsolutePath();

        final String baseStr = base.getAbsolutePath();
        // Don't allow relative paths.
        if (pathStr.contains("/.") ) {
            throw new IOException("Invalid path (was relative) : " + pathStr);
        }

        if (pathStr.startsWith(oldBaseStr)) {
            final String relative = pathStr.substring(oldBaseStr.length());
            return new File(newBase, relative);
        if (pathStr.startsWith(baseStr)) {
            return pathStr.substring(baseStr.length());
        }

        throw new IOException("File: " + pathStr + " outside base: " + oldBaseStr);
        throw new IOException("File: " + pathStr + " outside base: " + baseStr);
    }

    /**
     * Recreates a directory and file structure, specified by a list of files {@code fromFiles}
     * which are subpaths of {@code fromDir} to {@code toDir}. Directories are created with the
     * same permissions, and regular files are linked.
     *
     * TODO: Move this function to installd so that the system process doesn't have to
     * manipulate / relabel directories.
     */
    private static void createDirsAndLinkFiles(List<File> fromFiles, File toDir, File fromDir)
            throws IOException {
        for (File fromFile : fromFiles) {
            final File toFile = reparentPath(fromFile, fromDir, toDir);
            final StructStat stat;
            try {
                stat = Os.stat(fromFile.getAbsolutePath());
            } catch (ErrnoException e) {
                throw new IOException("Failed to stat: " + fromFile.getAbsolutePath(), e);
    private void createOatDirs(List<String> instructionSets, File fromDir) {
        for (String instructionSet : instructionSets) {
            mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
        }

            if (OsConstants.S_ISDIR(stat.st_mode)) {
                if (LOGD) Slog.d(TAG, "Creating directory " + toFile.getAbsolutePath());
                try {
                    Os.mkdir(toFile.getAbsolutePath(), stat.st_mode);
                } catch (ErrnoException e) {
                    throw new IOException("Failed to create dir: " + toFile.getAbsolutePath(), e);
    }

                // We do this to ensure that the oat/ directory is created with the right
                // label (data_dalvikcache_file) instead of apk_tmpfile.
                if (!SELinux.restorecon(toFile)) {
                    throw new IOException("Failed to restorecon: " + toFile.getAbsolutePath());
                }
            } else {
                if (LOGD) Slog.d(TAG, "Linking " + fromFile + " to " + toFile);
                try {
                    Os.link(fromFile.getAbsolutePath(), toFile.getAbsolutePath());
                } catch (ErrnoException e) {
                    throw new IOException("Failed to link " + fromFile + " to " + toFile, e);
                }
    private void linkFiles(List<File> fromFiles, File toDir, File fromDir)
            throws IOException {
        for (File fromFile : fromFiles) {
            final String relativePath = getRelativePath(fromFile, fromDir);
            final int ret = mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
                    toDir.getAbsolutePath());

            if (ret < 0) {
                // installd will log failure details.
                throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
                        + fromDir + ", " + toDir + ")");
            }
        }

        Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir);
    }