Merge "Set incremental apk directories"
This commit is contained in:
committed by
Android (Google) Code Review
commit
030536c8b8
@@ -23,8 +23,6 @@ import android.annotation.SystemService;
|
||||
import android.content.Context;
|
||||
import android.content.pm.DataLoaderParams;
|
||||
import android.os.RemoteException;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
@@ -193,116 +191,54 @@ public final class IncrementalManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames an Incremental path to a new path. If source path is a file, make a link from the old
|
||||
* Incremental file to the new one. If source path is a dir, unbind old dir from Incremental
|
||||
* Storage and bind the new one.
|
||||
* <ol>
|
||||
* <li> For renaming a dir, dest dir will be created if not exists, and does not need to
|
||||
* be on the same Incremental storage as the source. </li>
|
||||
* <li> For renaming a file, dest file must be on the same Incremental storage as source.
|
||||
* </li>
|
||||
* </ol>
|
||||
* Set up an app's code path. The expected outcome of this method is:
|
||||
* 1) The actual apk directory under /data/incremental is bind-mounted to the parent directory
|
||||
* of {@code afterCodeFile}.
|
||||
* 2) All the files under {@code beforeCodeFile} will show up under {@code afterCodeFile}.
|
||||
*
|
||||
* @param sourcePath Absolute path to the source. Should be the same type as the destPath (file
|
||||
* or dir). Expected to already exist and is an Incremental path.
|
||||
* @param destPath Absolute path to the destination.
|
||||
* @throws IllegalArgumentException when 1) source does not exist, or 2) source and dest type
|
||||
* mismatch (one is file and the other is dir), or 3) source
|
||||
* path is not on Incremental File System,
|
||||
* @throws IOException when 1) cannot find the root path of the Incremental storage
|
||||
* of source, or 2) cannot retrieve the Incremental storage
|
||||
* instance of the source, or 3) renaming a file, but dest is
|
||||
* not on the same Incremental Storage, or 4) renaming a dir,
|
||||
* dest dir does not exist but fails to be created.
|
||||
* <p>
|
||||
* TODO(b/136132412): add unit tests
|
||||
* @param beforeCodeFile Path that is currently bind-mounted and have APKs under it.
|
||||
* Should no longer have any APKs after this method is called.
|
||||
* Example: /data/app/vmdl*tmp
|
||||
* @param afterCodeFile Path that should will have APKs after this method is called. Its parent
|
||||
* directory should be bind-mounted to a directory under /data/incremental.
|
||||
* Example: /data/app/~~[randomStringA]/[packageName]-[randomStringB]
|
||||
* @throws IllegalArgumentException
|
||||
* @throws IOException
|
||||
* TODO(b/147371381): add unit tests
|
||||
*/
|
||||
public void rename(@NonNull String sourcePath, @NonNull String destPath) throws IOException {
|
||||
final File source = new File(sourcePath);
|
||||
final File dest = new File(destPath);
|
||||
if (!source.exists()) {
|
||||
throw new IllegalArgumentException("Path not exist: " + sourcePath);
|
||||
public void renameCodePath(File beforeCodeFile, File afterCodeFile)
|
||||
throws IllegalArgumentException, IOException {
|
||||
final String beforeCodePath = beforeCodeFile.getAbsolutePath();
|
||||
final String afterCodePathParent = afterCodeFile.getParentFile().getAbsolutePath();
|
||||
if (!isIncrementalPath(beforeCodePath)) {
|
||||
throw new IllegalArgumentException("Not an Incremental path: " + beforeCodePath);
|
||||
}
|
||||
if (dest.exists()) {
|
||||
throw new IllegalArgumentException("Target path already exists: " + destPath);
|
||||
final String afterCodePathName = afterCodeFile.getName();
|
||||
final Path apkStoragePath = Paths.get(beforeCodePath);
|
||||
if (apkStoragePath == null || apkStoragePath.toAbsolutePath() == null) {
|
||||
throw new IOException("Invalid source storage path for: " + beforeCodePath);
|
||||
}
|
||||
if (source.isDirectory() && dest.exists() && dest.isFile()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Trying to rename a dir but destination is a file: " + destPath);
|
||||
}
|
||||
if (source.isFile() && dest.exists() && dest.isDirectory()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Trying to rename a file but destination is a dir: " + destPath);
|
||||
}
|
||||
if (!isIncrementalPath(sourcePath)) {
|
||||
throw new IllegalArgumentException("Not an Incremental path: " + sourcePath);
|
||||
}
|
||||
|
||||
Path storagePath = Paths.get(sourcePath);
|
||||
if (source.isFile()) {
|
||||
storagePath = getStoragePathForFile(source);
|
||||
}
|
||||
if (storagePath == null || storagePath.toAbsolutePath() == null) {
|
||||
throw new IOException("Invalid source storage path for: " + sourcePath);
|
||||
}
|
||||
final IncrementalStorage storage = openStorage(storagePath.toAbsolutePath().toString());
|
||||
if (storage == null) {
|
||||
final IncrementalStorage apkStorage =
|
||||
openStorage(apkStoragePath.toAbsolutePath().toString());
|
||||
if (apkStorage == null) {
|
||||
throw new IOException("Failed to retrieve storage from Incremental Service.");
|
||||
}
|
||||
|
||||
if (source.isFile()) {
|
||||
renameFile(storage, storagePath, source, dest);
|
||||
} else {
|
||||
renameDir(storage, storagePath, source, dest);
|
||||
final IncrementalStorage linkedApkStorage = createStorage(afterCodePathParent, apkStorage,
|
||||
IncrementalManager.CREATE_MODE_CREATE
|
||||
| IncrementalManager.CREATE_MODE_PERMANENT_BIND);
|
||||
if (linkedApkStorage == null) {
|
||||
throw new IOException("Failed to create linked storage at dir: " + afterCodePathParent);
|
||||
}
|
||||
}
|
||||
|
||||
private void renameFile(IncrementalStorage storage, Path storagePath,
|
||||
File source, File dest) throws IOException {
|
||||
Path sourcePath = source.toPath();
|
||||
Path destPath = dest.toPath();
|
||||
if (!sourcePath.startsWith(storagePath)) {
|
||||
throw new IOException("Path: " + source.getAbsolutePath() + " is not on storage at: "
|
||||
+ storagePath.toString());
|
||||
}
|
||||
if (!destPath.startsWith(storagePath)) {
|
||||
throw new IOException("Path: " + dest.getAbsolutePath() + " is not on storage at: "
|
||||
+ storagePath.toString());
|
||||
}
|
||||
final Path sourceRelativePath = storagePath.relativize(sourcePath);
|
||||
final Path destRelativePath = storagePath.relativize(destPath);
|
||||
storage.moveFile(sourceRelativePath.toString(), destRelativePath.toString());
|
||||
|
||||
}
|
||||
|
||||
private void renameDir(IncrementalStorage storage, Path storagePath,
|
||||
File source, File dest) throws IOException {
|
||||
Path destPath = dest.toPath();
|
||||
boolean usedMkdir = false;
|
||||
try {
|
||||
Os.mkdir(dest.getAbsolutePath(), 0755);
|
||||
usedMkdir = true;
|
||||
} catch (ErrnoException e) {
|
||||
// Traditional mkdir fails but maybe we can create it on Incremental File System if
|
||||
// the dest path is on the same Incremental storage as the source.
|
||||
if (destPath.startsWith(storagePath)) {
|
||||
storage.makeDirectories(storagePath.relativize(destPath).toString());
|
||||
} else {
|
||||
throw new IOException("Failed to create directory: " + dest.getAbsolutePath(), e);
|
||||
linkedApkStorage.makeDirectory(afterCodePathName);
|
||||
File[] files = beforeCodeFile.listFiles();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
if (files[i].isFile()) {
|
||||
String fileName = files[i].getName();
|
||||
apkStorage.makeLink(
|
||||
fileName, linkedApkStorage, afterCodePathName + "/" + fileName);
|
||||
}
|
||||
}
|
||||
try {
|
||||
storage.moveDir(source.getAbsolutePath(), dest.getAbsolutePath());
|
||||
} catch (Exception ex) {
|
||||
if (usedMkdir) {
|
||||
try {
|
||||
Os.remove(dest.getAbsolutePath());
|
||||
} catch (ErrnoException ignored) {
|
||||
}
|
||||
}
|
||||
throw new IOException(
|
||||
"Failed to move " + source.getAbsolutePath() + " to " + dest.getAbsolutePath());
|
||||
}
|
||||
apkStorage.unBind(beforeCodePath);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14999,9 +14999,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
||||
try {
|
||||
makeDirRecursive(afterCodeFile.getParentFile(), 0775);
|
||||
if (onIncremental) {
|
||||
// TODO(b/147371381): fix incremental installation
|
||||
mIncrementalManager.rename(beforeCodeFile.getAbsolutePath(),
|
||||
afterCodeFile.getAbsolutePath());
|
||||
mIncrementalManager.renameCodePath(beforeCodeFile, afterCodeFile);
|
||||
} else {
|
||||
Os.rename(beforeCodeFile.getAbsolutePath(), afterCodeFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user