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

* commit 'fb89df9fc220245a0ac5e3923acae2b6308d9edc':
  Move linking and directory creation logic to installd.
This commit is contained in:
Narayan Kamath
2015-06-09 13:02:22 +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());
}
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.
*/

View File

@@ -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,21 +712,23 @@ 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.
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());
if (!oatFiles.isEmpty()) {
mResolvedInheritedFiles.add(archSubDir);
mResolvedInheritedFiles.addAll(oatFiles);
// 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) {
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;
}
/**
* 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)
private void createOatDirs(List<String> instructionSets, File fromDir) {
for (String instructionSet : instructionSets) {
mPm.mInstaller.createOatDir(fromDir.getAbsolutePath(), instructionSet);
}
}
private void linkFiles(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);
}
final String relativePath = getRelativePath(fromFile, fromDir);
final int ret = mPm.mInstaller.linkFile(relativePath, fromDir.getAbsolutePath(),
toDir.getAbsolutePath());
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);
}
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);
}