am 3eb63dc3: Merge "Move linking and directory creation logic to installd." into mnc-dev

* commit '3eb63dc35e7ac0335defe4f8e7b42f5dcc390b42':
  Move linking and directory creation logic to installd.
This commit is contained in:
Narayan Kamath
2015-06-09 12:50:01 +00:00
committed by Android Git Automerger
2 changed files with 55 additions and 65 deletions

View File

@@ -454,6 +454,18 @@ public final class Installer extends SystemService {
return mInstaller.execute(builder.toString()); 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. * Returns true iff. {@code instructionSet} is a valid instruction set.
*/ */

View File

@@ -166,6 +166,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@GuardedBy("mLock") @GuardedBy("mLock")
private final List<File> mResolvedInheritedFiles = new ArrayList<>(); private final List<File> mResolvedInheritedFiles = new ArrayList<>();
@GuardedBy("mLock") @GuardedBy("mLock")
private final List<String> mResolvedInstructionSets = new ArrayList<>();
@GuardedBy("mLock")
private File mInheritedFilesBase; private File mInheritedFilesBase;
private final Handler.Callback mHandlerCallback = new Handler.Callback() { private final Handler.Callback mHandlerCallback = new Handler.Callback() {
@@ -521,7 +523,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
} }
if (isLinkPossible(fromFiles, toDir)) { 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 { } else {
// TODO: this should delegate to DCS so the system process // TODO: this should delegate to DCS so the system process
// avoids holding open FDs into containers. // avoids holding open FDs into containers.
@@ -706,21 +712,23 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
final File oatDir = new File(packageInstallDir, "oat"); final File oatDir = new File(packageInstallDir, "oat");
if (oatDir.exists()) { if (oatDir.exists()) {
final File[] archSubdirs = oatDir.listFiles(); final File[] archSubdirs = oatDir.listFiles();
// Only add "oatDir" if it contains arch specific subdirs.
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.
if (!ArrayUtils.contains(instructionSets, archSubDir.getName())) {
continue;
}
List<File> oatFiles = Arrays.asList(archSubDir.listFiles()); // Keep track of all instruction sets we've seen compiled output for.
if (!oatFiles.isEmpty()) { // If we're linking (and not copying) inherited files, we can recreate the
mResolvedInheritedFiles.add(archSubDir); // instruction set hierarchy and link compiled output.
mResolvedInheritedFiles.addAll(oatFiles); if (archSubdirs != null && archSubdirs.length > 0) {
final String[] instructionSets = InstructionSets.getAllDexCodeInstructionSets();
for (File archSubDir : archSubdirs) {
// Skip any directory that isn't an ISA subdir.
if (!ArrayUtils.contains(instructionSets, archSubDir.getName())) {
continue;
}
mResolvedInstructionSets.add(archSubDir.getName());
List<File> oatFiles = Arrays.asList(archSubDir.listFiles());
if (!oatFiles.isEmpty()) {
mResolvedInheritedFiles.addAll(oatFiles);
}
} }
} }
} }
@@ -802,71 +810,41 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
return true; return true;
} }
/** private static String getRelativePath(File file, File base) throws IOException {
* 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();
final String pathStr = file.getAbsolutePath(); final String pathStr = file.getAbsolutePath();
final String baseStr = base.getAbsolutePath();
// Don't allow relative paths. // Don't allow relative paths.
if (pathStr.contains("/.") ) { if (pathStr.contains("/.") ) {
throw new IOException("Invalid path (was relative) : " + pathStr); throw new IOException("Invalid path (was relative) : " + pathStr);
} }
if (pathStr.startsWith(oldBaseStr)) { if (pathStr.startsWith(baseStr)) {
final String relative = pathStr.substring(oldBaseStr.length()); return pathStr.substring(baseStr.length());
return new File(newBase, relative);
} }
throw new IOException("File: " + pathStr + " outside base: " + oldBaseStr); throw new IOException("File: " + pathStr + " outside base: " + baseStr);
} }
/** private void createOatDirs(List<String> instructionSets, File fromDir) {
* Recreates a directory and file structure, specified by a list of files {@code fromFiles} for (String instructionSet : instructionSets) {
* which are subpaths of {@code fromDir} to {@code toDir}. Directories are created with the mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
* 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 void linkFiles(List<File> fromFiles, File toDir, File fromDir)
*/
private static void createDirsAndLinkFiles(List<File> fromFiles, File toDir, File fromDir)
throws IOException { throws IOException {
for (File fromFile : fromFiles) { for (File fromFile : fromFiles) {
final File toFile = reparentPath(fromFile, fromDir, toDir); final String relativePath = getRelativePath(fromFile, fromDir);
final StructStat stat; final int ret = mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
try { toDir.getAbsolutePath());
stat = Os.stat(fromFile.getAbsolutePath());
} catch (ErrnoException e) {
throw new IOException("Failed to stat: " + fromFile.getAbsolutePath(), e);
}
if (OsConstants.S_ISDIR(stat.st_mode)) { if (ret < 0) {
if (LOGD) Slog.d(TAG, "Creating directory " + toFile.getAbsolutePath()); // installd will log failure details.
try { throw new IOException("failed linkOrCreateDir(" + relativePath + ", "
Os.mkdir(toFile.getAbsolutePath(), stat.st_mode); + fromDir + ", " + toDir + ")");
} 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);
}
} }
} }
Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir); Slog.d(TAG, "Linked " + fromFiles.size() + " files into " + toDir);
} }