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:
@@ -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) {
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user