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