Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f2ed0271 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Unifying non-incremental and incremental."

parents c69d2c85 c5682f5b
Loading
Loading
Loading
Loading
+88 −67
Original line number Diff line number Diff line
@@ -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,22 +67,68 @@ 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;
            if (TextUtils.isEmpty(mDefaultDir)) {
                throw new IOException("Failed to create storage: incrementalPath is empty");
            }
            mDefaultStorage = mIncrementalManager.openStorage(incrementalPath);
        } else {
            mDefaultDir = getTempDir();
            if (mDefaultDir == null) {
            return;
                throw new IOException("Failed to create storage: tempDir is empty");
            }
            mDefaultStorage = mIncrementalManager.createStorage(mDefaultDir,
                    dataLoaderParams,
@@ -84,18 +136,8 @@ public final class IncrementalFileStorages {
                            | 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);
        } else {
            throw new IOException("Unknown file type: " + file.getFileType());
            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) {
        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) {
+13 −34
Original line number Diff line number Diff line
@@ -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) {
        // TODO(b/136132412): update with new APIs
        if (isIncrementalInstallation()) {
            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);
                }
            }
                mIncrementalFileStorages = IncrementalFileStorages.initialize(mContext,
                        stageDir, params.dataLoaderParams, addedFiles);
                return true;
            } catch (IOException e) {
                throw new PackageManagerException(e);
            }
        }

        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());