Loading core/java/android/os/incremental/IncrementalManager.java +39 −103 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } if (dest.exists()) { throw new IllegalArgumentException("Target path already exists: " + destPath); } 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) { 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); } 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); } 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); } } 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); } } try { storage.moveDir(source.getAbsolutePath(), dest.getAbsolutePath()); } catch (Exception ex) { if (usedMkdir) { try { Os.remove(dest.getAbsolutePath()); } catch (ErrnoException ignored) { 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); } 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); } throw new IOException( "Failed to move " + source.getAbsolutePath() + " to " + dest.getAbsolutePath()); } apkStorage.unBind(beforeCodePath); } /** Loading services/core/java/com/android/server/pm/PackageManagerService.java +1 −3 Original line number Diff line number Diff line Loading @@ -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()); } Loading
core/java/android/os/incremental/IncrementalManager.java +39 −103 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } if (dest.exists()) { throw new IllegalArgumentException("Target path already exists: " + destPath); } 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) { 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); } 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); } 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); } } 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); } } try { storage.moveDir(source.getAbsolutePath(), dest.getAbsolutePath()); } catch (Exception ex) { if (usedMkdir) { try { Os.remove(dest.getAbsolutePath()); } catch (ErrnoException ignored) { 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); } 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); } throw new IOException( "Failed to move " + source.getAbsolutePath() + " to " + dest.getAbsolutePath()); } apkStorage.unBind(beforeCodePath); } /** Loading
services/core/java/com/android/server/pm/PackageManagerService.java +1 −3 Original line number Diff line number Diff line Loading @@ -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()); }