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

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

Merge "DataLoader version of installation API."

parents 0c9a5483 da208155
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -39,6 +39,9 @@ interface IPackageInstallerSession {
    void transfer(in String packageName, in IntentSender statusReceiver);
    void abandon();

    void addFile(String name, long lengthBytes, in byte[] metadata);
    void removeFile(String name);

    boolean isMultiPackage();
    int[] getChildSessionIds();
    void addChildSessionId(in int sessionId);
@@ -46,5 +49,4 @@ interface IPackageInstallerSession {
    int getParentSessionId();

    boolean isStaged();
    void addFile(in String name, long size, in byte[] metadata);
}
+75 −23
Original line number Diff line number Diff line
@@ -230,6 +230,15 @@ public class PackageInstaller {
    /** {@hide} */
    public static final String EXTRA_CALLBACK = "android.content.pm.extra.CALLBACK";

    /**
     * Streaming installation pending.
     * Caller should make sure DataLoader is able to prepare image and reinitiate the operation.
     *
     * @see #EXTRA_SESSION_ID
     * {@hide}
     */
    public static final int STATUS_PENDING_STREAMING = -2;

    /**
     * User action is currently required to proceed. You can launch the intent
     * activity described by {@link Intent#EXTRA_INTENT} to involve the user and
@@ -1059,13 +1068,56 @@ public class PackageInstaller {
            }
        }


        /**
         * Adds a file to session. On commit this file will be pulled from dataLoader.
         *
         * @param name arbitrary, unique name of your choosing to identify the
         *            APK being written. You can open a file again for
         *            additional writes (such as after a reboot) by using the
         *            same name. This name is only meaningful within the context
         *            of a single install session.
         * @param lengthBytes total size of the file being written.
         *            The system may clear various caches as needed to allocate
         *            this space.
         * @param metadata additional info use by dataLoader to pull data for the file.
         * @throws SecurityException if called after the session has been
         *             sealed or abandoned
         * @throws IllegalStateException if called for non-callback session
         * {@hide}
         */
        public void addFile(@NonNull String name, long lengthBytes, @NonNull byte[] metadata) {
            try {
                mSession.addFile(name, lengthBytes, metadata);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }

        /**
         * Removes a file.
         *
         * @param name name of a file, e.g. split.
         * @throws SecurityException if called after the session has been
         *             sealed or abandoned
         * @throws IllegalStateException if called for non-callback session
         * {@hide}
         */
        public void removeFile(@NonNull String name) {
            try {
                mSession.removeFile(name);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }

        /**
         * Attempt to commit everything staged in this session. This may require
         * user intervention, and so it may not happen immediately. The final
         * result of the commit will be reported through the given callback.
         * <p>
         * Once this method is called, the session is sealed and no additional
         * mutations may be performed on the session. If the device reboots
         * Once this method is called, the session is sealed and no additional mutations may be
         * performed on the session. In case of device reboot or data loader transient failure
         * before the session has been finalized, you may commit the session again.
         * <p>
         * If the installer is the device owner or the affiliated profile owner, there will be no
@@ -1219,27 +1271,6 @@ public class PackageInstaller {
            }
        }

        /**
         * Configure files for an installation session.
         *
         * Currently only for Incremental installation session. Once this method is called,
         * the files and their paths, as specified in the parameters, will be created and properly
         * configured in the Incremental File System.
         *
         * TODO(b/136132412): update this and InstallationFile class with latest API design.
         *
         * @throws IllegalStateException if {@link SessionParams#incrementalParams} is null.
         *
         * @hide
         */
        public void addFile(@NonNull String name, long size, @NonNull byte[] metadata) {
            try {
                mSession.addFile(name, size, metadata);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }

        /**
         * Release this session object. You can open the session again if it
         * hasn't been finalized.
@@ -1429,6 +1460,9 @@ public class PackageInstaller {
        public long requiredInstalledVersionCode = PackageManager.VERSION_CODE_HIGHEST;
        /** {@hide} */
        public IncrementalDataLoaderParams incrementalParams;
        /** TODO(b/146080380): add a class name to make it fully compatible with ComponentName.
         * {@hide} */
        public String dataLoaderPackageName;

        /**
         * Construct parameters for a new package install session.
@@ -1468,6 +1502,7 @@ public class PackageInstaller {
                incrementalParams = new IncrementalDataLoaderParams(
                        dataLoaderParamsParcel);
            }
            dataLoaderPackageName = source.readString();
        }

        /** {@hide} */
@@ -1492,6 +1527,7 @@ public class PackageInstaller {
            ret.isStaged = isStaged;
            ret.requiredInstalledVersionCode = requiredInstalledVersionCode;
            ret.incrementalParams = incrementalParams;
            ret.dataLoaderPackageName = dataLoaderPackageName;
            return ret;
        }

@@ -1831,6 +1867,20 @@ public class PackageInstaller {
            this.incrementalParams = incrementalParams;
        }

        /**
         * Set the data provider params for the session.
         * This also switches installation into callback mode and disallow direct writes into
         * staging folder.
         * TODO(b/146080380): unify dataprovider params with Incremental.
         *
         * @param dataLoaderPackageName name of the dataLoader package
         * {@hide}
         */
        @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
        public void setDataLoaderPackageName(String dataLoaderPackageName) {
            this.dataLoaderPackageName = dataLoaderPackageName;
        }

        /** {@hide} */
        public void dump(IndentingPrintWriter pw) {
            pw.printPair("mode", mode);
@@ -1851,6 +1901,7 @@ public class PackageInstaller {
            pw.printPair("isMultiPackage", isMultiPackage);
            pw.printPair("isStaged", isStaged);
            pw.printPair("requiredInstalledVersionCode", requiredInstalledVersionCode);
            pw.printPair("dataLoaderPackageName", dataLoaderPackageName);
            pw.println();
        }

@@ -1885,6 +1936,7 @@ public class PackageInstaller {
            } else {
                dest.writeParcelable(null, flags);
            }
            dest.writeString(dataLoaderPackageName);
        }

        public static final Parcelable.Creator<SessionParams>
+19 −3
Original line number Diff line number Diff line
@@ -637,7 +637,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
        session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this,
                mInstallThread.getLooper(), mStagingManager, sessionId, userId, callingUid,
                installSource, params, createdMillis,
                stageDir, stageCid, false, false, false, null, SessionInfo.INVALID_ID,
                stageDir, stageCid, null, false, false, false, null, SessionInfo.INVALID_ID,
                false, false, false, SessionInfo.STAGED_SESSION_NO_ERROR, "");

        synchronized (mSessions) {
@@ -1014,12 +1014,28 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
        }
    }

    static void sendPendingStreaming(Context context, IntentSender target, int sessionId,
            Throwable cause) {
        final Intent intent = new Intent();
        intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
        intent.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_PENDING_STREAMING);
        if (cause != null && !TextUtils.isEmpty(cause.getMessage())) {
            intent.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE,
                    "Staging Image Not Ready [" + cause.getMessage() + "]");
        } else {
            intent.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, "Staging Image Not Ready");
        }
        try {
            target.sendIntent(context, 0, intent, null, null);
        } catch (SendIntentException ignored) {
        }
    }

    static void sendOnUserActionRequired(Context context, IntentSender target, int sessionId,
            Intent intent) {
        final Intent fillIn = new Intent();
        fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
        fillIn.putExtra(PackageInstaller.EXTRA_STATUS,
                PackageInstaller.STATUS_PENDING_USER_ACTION);
        fillIn.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_PENDING_USER_ACTION);
        fillIn.putExtra(Intent.EXTRA_INTENT, intent);
        try {
            target.sendIntent(context, 0, fillIn, null, null);
+309 −47

File changed.

Preview size limit exceeded, changes collapsed.

+58 −10
Original line number Diff line number Diff line
@@ -114,6 +114,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -135,6 +136,8 @@ class PackageManagerShellCommand extends ShellCommand {
    private final static String ART_PROFILE_SNAPSHOT_DEBUG_LOCATION = "/data/misc/profman/";
    private static final int DEFAULT_WAIT_MS = 60 * 1000;

    private static final String PM_SHELL_DATALOADER = "com.android.pm.dataloader";

    final IPackageManager mInterface;
    final IPermissionManager mPermissionManager;
    final private WeakHashMap<String, Resources> mResourceCache =
@@ -175,6 +178,8 @@ class PackageManagerShellCommand extends ShellCommand {
                    return runQueryIntentReceivers();
                case "install":
                    return runInstall();
                case "install-streaming":
                    return runStreamingInstall();
                case "install-abandon":
                case "install-destroy":
                    return runInstallAbandon();
@@ -1152,9 +1157,21 @@ class PackageManagerShellCommand extends ShellCommand {
        return 0;
    }

    private int runStreamingInstall() throws RemoteException {
        final InstallParams params = makeInstallParams();
        if (TextUtils.isEmpty(params.sessionParams.dataLoaderPackageName)) {
            params.sessionParams.setDataLoaderPackageName(PM_SHELL_DATALOADER);
        }
        return doRunInstall(params);
    }

    private int runInstall() throws RemoteException {
        return doRunInstall(makeInstallParams());
    }

    private int doRunInstall(final InstallParams params) throws RemoteException {
        final PrintWriter pw = getOutPrintWriter();
        final InstallParams params = makeInstallParams();
        final boolean streaming = !TextUtils.isEmpty(params.sessionParams.dataLoaderPackageName);

        ArrayList<String> inPaths = getRemainingArgs();
        if (inPaths.isEmpty()) {
@@ -1181,19 +1198,32 @@ class PackageManagerShellCommand extends ShellCommand {
            return 1;
        }

        if (!streaming) {
            setParamsSize(params, inPaths);
        }

        final int sessionId = doCreateSession(params.sessionParams,
                params.installerPackageName, params.userId);
        boolean abandonSession = true;
        try {
            for (String inPath : inPaths) {
                String splitName = hasSplits ? (new File(inPath)).getName()
                if (streaming) {
                    String name = new File(inPath).getName();
                    byte[] metadata = inPath.getBytes(StandardCharsets.UTF_8);
                    if (doAddFile(sessionId, name, params.sessionParams.sizeBytes, metadata,
                            false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
                        return 1;
                    }
                } else {
                    String splitName = hasSplits ? new File(inPath).getName()
                            : "base." + (isApex ? "apex" : "apk");

                    if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, splitName,
                            false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) {
                        return 1;
                    }
                }
            }
            if (doCommitSession(sessionId, false /*logSuccess*/)
                    != PackageInstaller.STATUS_SUCCESS) {
                return 1;
@@ -2927,11 +2957,32 @@ class PackageManagerShellCommand extends ShellCommand {
        return sessionId;
    }

    private int doAddFile(int sessionId, String name, long sizeBytes, byte[] metadata,
            boolean logSuccess) throws RemoteException {
        PackageInstaller.Session session = new PackageInstaller.Session(
                mInterface.getPackageInstaller().openSession(sessionId));
        try {
            session.addFile(name, sizeBytes, metadata);

            if (logSuccess) {
                getOutPrintWriter().println("Success");
            }

            return 0;
        } finally {
            IoUtils.closeQuietly(session);
        }
    }

    private int doWriteSplit(int sessionId, String inPath, long sizeBytes, String splitName,
            boolean logSuccess) throws RemoteException {
        PackageInstaller.Session session = null;
        try {
            session = new PackageInstaller.Session(
                    mInterface.getPackageInstaller().openSession(sessionId));

            final PrintWriter pw = getOutPrintWriter();

            final ParcelFileDescriptor fd;
            if (STDIN_PATH.equals(inPath)) {
                fd = ParcelFileDescriptor.dup(getInFileDescriptor());
@@ -2953,8 +3004,6 @@ class PackageManagerShellCommand extends ShellCommand {
                return 1;
            }

            session = new PackageInstaller.Session(
                    mInterface.getPackageInstaller().openSession(sessionId));
            session.write(splitName, 0, sizeBytes, fd);

            if (logSuccess) {
@@ -3000,7 +3049,6 @@ class PackageManagerShellCommand extends ShellCommand {
        try {
            session = new PackageInstaller.Session(
                    mInterface.getPackageInstaller().openSession(sessionId));

            for (String splitName : splitNames) {
                session.removeSplit(splitName);
            }
Loading