Unifying non-incremental and incremental.

Step 1 moving all Incremental code into prepareDataLoaderLocked - where
non-incremental DataLoader calls reside.

Test: atest PackageManagerShellCommandTest
Bug: b/136132412 b/133435829 b/136132412
Change-Id: Icf670de6d4802bf52cd4a93fa4475629d9ac9bc0
This commit is contained in:
Alex Buynytskyy
2020-01-30 13:17:05 -08:00
parent dea8db3d54
commit c5682f5b68
2 changed files with 103 additions and 103 deletions

View File

@@ -17,24 +17,24 @@
package android.os.incremental;
/**
* Set up files and directories used in an installation session.
* Currently only used by Incremental Installation.
* For Incremental installation, the expected outcome of this function is:
* 0) All the files are in defaultStorage
* 1) All APK files are in the same directory, bound to mApkStorage, and bound to the
* InstallerSession's stage dir. The files are linked from mApkStorage to defaultStorage.
* 2) All lib files are in the sub directories as their names suggest, and in the same parent
* directory as the APK files. The files are linked from mApkStorage to defaultStorage.
* 3) OBB files are in another directory that is different from APK files and lib files, bound
* to mObbStorage. The files are linked from mObbStorage to defaultStorage.
* Set up files and directories used in an installation session. Currently only used by Incremental
* Installation. For Incremental installation, the expected outcome of this function is: 0) All the
* files are in defaultStorage 1) All APK files are in the same directory, bound to mApkStorage, and
* bound to the InstallerSession's stage dir. The files are linked from mApkStorage to
* defaultStorage. 2) All lib files are in the sub directories as their names suggest, and in the
* same parent directory as the APK files. The files are linked from mApkStorage to defaultStorage.
* 3) OBB files are in another directory that is different from APK files and lib files, bound to
* mObbStorage. The files are linked from mObbStorage to defaultStorage.
*
* @throws IllegalStateException the session is not an Incremental installation session.
*/
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.DataLoaderParams;
import android.content.pm.InstallationFile;
import android.text.TextUtils;
import android.util.Slog;
import java.io.File;
@@ -42,6 +42,8 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Objects;
import java.util.Random;
/**
@@ -50,6 +52,10 @@ import java.util.Random;
*/
public final class IncrementalFileStorages {
private static final String TAG = "IncrementalFileStorages";
private static final String TMP_DIR_ROOT = "/data/incremental/tmp";
private static final Random TMP_DIR_RANDOM = new Random();
private @Nullable IncrementalStorage mDefaultStorage;
private @Nullable String mDefaultDir;
private @NonNull IncrementalManager mIncrementalManager;
@@ -61,41 +67,77 @@ public final class IncrementalFileStorages {
* TODO(b/133435829): code clean up
*
* @throws IllegalStateException the session is not an Incremental installation session.
* @throws IOException if fails to setup files or directories.
*/
public IncrementalFileStorages(@NonNull String packageName,
public static IncrementalFileStorages initialize(Context context,
@NonNull File stageDir,
@NonNull DataLoaderParams dataLoaderParams,
List<InstallationFile> addedFiles) throws IOException {
// TODO(b/136132412): sanity check if session should not be incremental
IncrementalManager incrementalManager = (IncrementalManager) context.getSystemService(
Context.INCREMENTAL_SERVICE);
if (incrementalManager == null) {
// TODO(b/146080380): add incremental-specific error code
throw new IOException("Failed to obtain incrementalManager.");
}
IncrementalFileStorages result = null;
try {
result = new IncrementalFileStorages(stageDir, incrementalManager, dataLoaderParams);
for (InstallationFile file : addedFiles) {
if (file.getFileType() == InstallationFile.FILE_TYPE_APK) {
try {
result.addApkFile(file);
} catch (IOException e) {
// TODO(b/146080380): add incremental-specific error code
throw new IOException(
"Failed to add and configure Incremental File: " + file.getName(),
e);
}
} else {
throw new IOException("Unknown file type: " + file.getFileType());
}
}
if (!result.mDefaultStorage.startLoading()) {
// TODO(b/146080380): add incremental-specific error code
throw new IOException("Failed to start loading data for Incremental installation.");
}
return result;
} catch (IOException e) {
if (result != null) {
result.cleanUp();
}
throw e;
}
}
private IncrementalFileStorages(@NonNull File stageDir,
@NonNull IncrementalManager incrementalManager,
@NonNull DataLoaderParams dataLoaderParams) {
@NonNull DataLoaderParams dataLoaderParams) throws IOException {
mStageDir = stageDir;
mIncrementalManager = incrementalManager;
if (dataLoaderParams.getComponentName().getPackageName().equals("local")) {
final String incrementalPath = dataLoaderParams.getArguments();
mDefaultStorage = mIncrementalManager.openStorage(incrementalPath);
mDefaultDir = incrementalPath;
return;
}
mDefaultDir = getTempDir();
if (mDefaultDir == null) {
return;
}
mDefaultStorage = mIncrementalManager.createStorage(mDefaultDir,
dataLoaderParams,
IncrementalManager.CREATE_MODE_CREATE
| IncrementalManager.CREATE_MODE_TEMPORARY_BIND, false);
}
/**
* Adds a file into the installation session. Makes sure it will be placed inside
* a proper storage instance, based on its file type.
*/
public void addFile(@NonNull InstallationFile file) throws IOException {
if (mDefaultStorage == null) {
throw new IOException("Cannot add file because default storage does not exist");
}
if (file.getFileType() == InstallationFile.FILE_TYPE_APK) {
addApkFile(file);
if (TextUtils.isEmpty(mDefaultDir)) {
throw new IOException("Failed to create storage: incrementalPath is empty");
}
mDefaultStorage = mIncrementalManager.openStorage(incrementalPath);
} else {
throw new IOException("Unknown file type: " + file.getFileType());
mDefaultDir = getTempDir();
if (mDefaultDir == null) {
throw new IOException("Failed to create storage: tempDir is empty");
}
mDefaultStorage = mIncrementalManager.createStorage(mDefaultDir,
dataLoaderParams,
IncrementalManager.CREATE_MODE_CREATE
| IncrementalManager.CREATE_MODE_TEMPORARY_BIND, false);
}
if (mDefaultStorage == null) {
throw new IOException("Failed to create storage");
}
}
@@ -108,26 +150,6 @@ public final class IncrementalFileStorages {
mDefaultStorage.makeFile(apkName, apk.getSize(), null,
apk.getMetadata(), 0, null, null, null);
}
if (targetFile.exists()) {
Slog.i(TAG, "!!! created: " + targetFile.getAbsolutePath());
}
}
/**
* Starts loading data for default storage.
* TODO(b/136132412): update the implementation with latest API design.
*/
public boolean startLoading() {
if (mDefaultStorage == null) {
return false;
}
return mDefaultStorage.startLoading();
}
/**
* Sets up obb storage directory and create bindings.
*/
public void finishSetUp() {
}
/**
@@ -135,22 +157,21 @@ public final class IncrementalFileStorages {
* TODO(b/136132412): make sure unnecessary binds are removed but useful storages are kept
*/
public void cleanUp() {
if (mDefaultStorage != null && mDefaultDir != null) {
try {
mDefaultStorage.unBind(mDefaultDir);
mDefaultStorage.unBind(mStageDir.getAbsolutePath());
} catch (IOException ignored) {
}
mDefaultDir = null;
mDefaultStorage = null;
Objects.requireNonNull(mDefaultStorage);
try {
mDefaultStorage.unBind(mDefaultDir);
mDefaultStorage.unBind(mStageDir.getAbsolutePath());
} catch (IOException ignored) {
}
mDefaultDir = null;
mDefaultStorage = null;
}
private String getTempDir() {
final String tmpDirRoot = "/data/incremental/tmp";
final Random random = new Random();
final Path tmpDir =
Paths.get(tmpDirRoot, String.valueOf(random.nextInt(Integer.MAX_VALUE - 1)));
private static String getTempDir() {
final Path tmpDir = Paths.get(TMP_DIR_ROOT,
String.valueOf(TMP_DIR_RANDOM.nextInt(Integer.MAX_VALUE - 1)));
try {
Files.createDirectories(tmpDir);
} catch (Exception ex) {

View File

@@ -101,7 +101,6 @@ import android.os.RevocableFileDescriptor;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.incremental.IncrementalFileStorages;
import android.os.incremental.IncrementalManager;
import android.os.storage.StorageManager;
import android.provider.Settings.Secure;
import android.stats.devicepolicy.DevicePolicyEnums;
@@ -559,17 +558,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mStagedSessionErrorMessage =
stagedSessionErrorMessage != null ? stagedSessionErrorMessage : "";
// TODO(b/136132412): sanity check if session should not be incremental
if (!params.isStaged && isIncrementalInstallation()) {
IncrementalManager incrementalManager = (IncrementalManager) mContext.getSystemService(
Context.INCREMENTAL_SERVICE);
if (incrementalManager != null) {
mIncrementalFileStorages =
new IncrementalFileStorages(mPackageName, stageDir, incrementalManager,
params.dataLoaderParams);
}
}
if (isStreamingInstallation()
&& this.params.dataLoaderParams.getComponentName().getPackageName()
== SYSTEM_DATA_LOADER_PACKAGE) {
@@ -1040,10 +1028,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
if (mIncrementalFileStorages != null) {
mIncrementalFileStorages.finishSetUp();
}
dispatchStreamValidateAndCommit();
}
@@ -1052,11 +1036,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
private void handleStreamValidateAndCommit() {
// TODO(b/136132412): update with new APIs
if (mIncrementalFileStorages != null) {
mIncrementalFileStorages.startLoading();
}
boolean success = streamValidateAndCommit();
if (isMultiPackage()) {
@@ -2476,17 +2455,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
}
if (mIncrementalFileStorages != null) {
for (InstallationFile file : addedFiles) {
try {
mIncrementalFileStorages.addFile(file);
} catch (IOException ex) {
// TODO(b/146080380): add incremental-specific error code
throw new PackageManagerException(INSTALL_FAILED_INTERNAL_ERROR,
"Failed to add and configure Incremental File: " + file.getName(), ex);
}
// TODO(b/136132412): update with new APIs
if (isIncrementalInstallation()) {
try {
mIncrementalFileStorages = IncrementalFileStorages.initialize(mContext,
stageDir, params.dataLoaderParams, addedFiles);
return true;
} catch (IOException e) {
throw new PackageManagerException(e);
}
return true;
}
final DataLoaderManager dataLoaderManager = mContext.getSystemService(
@@ -2761,13 +2738,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
bridge.forceClose();
}
}
if (mIncrementalFileStorages != null) {
mIncrementalFileStorages.cleanUp();
mIncrementalFileStorages = null;
}
// For staged sessions, we don't delete the directory where the packages have been copied,
// since these packages are supposed to be read on reboot.
// Those dirs are deleted when the staged session has reached a final state.
if (stageDir != null && !params.isStaged) {
if (mIncrementalFileStorages != null) {
mIncrementalFileStorages.cleanUp();
}
try {
mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());
} catch (InstallerException ignored) {
@@ -2783,6 +2761,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
} else {
if (mIncrementalFileStorages != null) {
mIncrementalFileStorages.cleanUp();
mIncrementalFileStorages = null;
}
try {
mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath());