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:
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user