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

Commit b8edc679 authored by Oli Lan's avatar Oli Lan Committed by Android (Google) Code Review
Browse files

Merge "Add rollback parameters when submitting sessions to apexd."

parents e754074a c72b0bba
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -946,7 +946,8 @@ public abstract class PackageManager {
            INSTALL_REASON_POLICY,
            INSTALL_REASON_DEVICE_RESTORE,
            INSTALL_REASON_DEVICE_SETUP,
            INSTALL_REASON_USER
            INSTALL_REASON_USER,
            INSTALL_REASON_ROLLBACK
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface InstallReason {}
@@ -976,6 +977,13 @@ public abstract class PackageManager {
     */
    public static final int INSTALL_REASON_USER = 4;

    /**
     * Code indicating that the package installation was a rollback initiated by RollbackManager.
     *
     * @hide
     */
    public static final int INSTALL_REASON_ROLLBACK = 5;

    /**
     * @hide
     */
+2 −1
Original line number Diff line number Diff line
@@ -44,9 +44,10 @@ interface IRollbackManager {
    // Used by the staging manager to notify the RollbackManager that a session is
    // being staged. In the case of multi-package sessions, the specified sessionId
    // is that of the parent session.
    // Returns the rollback id if rollback was enabled successfully, or -1 if not.
    //
    // NOTE: This call is synchronous.
    boolean notifyStagedSession(int sessionId);
    int notifyStagedSession(int sessionId);

    // Used by the staging manager to notify the RollbackManager of the apk
    // session for a staged session.
+5 −10
Original line number Diff line number Diff line
@@ -17,11 +17,11 @@
package com.android.server.pm;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.apex.ApexInfo;
import android.apex.ApexInfoList;
import android.apex.ApexSessionInfo;
import android.apex.ApexSessionParams;
import android.apex.IApexService;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -176,13 +176,9 @@ abstract class ApexManager {
     * enough for it to be activated at the next boot, the caller needs to call
     * {@link #markStagedSessionReady(int)}.
     *
     * @param sessionId the identifier of the {@link PackageInstallerSession} being submitted.
     * @param childSessionIds if {@code sessionId} is a multi-package session, this should contain
     *                        an array of identifiers of all the child sessions. Otherwise it should
     *                        be an empty array.
     * @throws PackageManagerException if call to apexd fails
     */
    abstract ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds)
    abstract ApexInfoList submitStagedSession(ApexSessionParams params)
            throws PackageManagerException;

    /**
@@ -450,11 +446,10 @@ abstract class ApexManager {
        }

        @Override
        ApexInfoList submitStagedSession(int sessionId, @NonNull int[] childSessionIds)
                throws PackageManagerException {
        ApexInfoList submitStagedSession(ApexSessionParams params) throws PackageManagerException {
            try {
                final ApexInfoList apexInfoList = new ApexInfoList();
                mApexService.submitStagedSession(sessionId, childSessionIds, apexInfoList);
                mApexService.submitStagedSession(params, apexInfoList);
                return apexInfoList;
            } catch (RemoteException re) {
                Slog.e(TAG, "Unable to contact apexservice", re);
@@ -686,7 +681,7 @@ abstract class ApexManager {
        }

        @Override
        ApexInfoList submitStagedSession(int sessionId, int[] childSessionIds)
        ApexInfoList submitStagedSession(ApexSessionParams params)
                throws PackageManagerException {
            throw new PackageManagerException(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
                    "Device doesn't support updating APEX");
+61 −23
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.apex.ApexInfo;
import android.apex.ApexInfoList;
import android.apex.ApexSessionInfo;
import android.apex.ApexSessionParams;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
@@ -36,6 +37,8 @@ import android.content.pm.PackageParser.SigningDetails;
import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
import android.content.pm.ParceledListSlice;
import android.content.rollback.IRollbackManager;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -49,6 +52,7 @@ import android.os.storage.StorageManager;
import android.util.IntArray;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.util.apk.ApkSignatureVerifier;

import com.android.internal.annotations.GuardedBy;
@@ -82,6 +86,9 @@ public class StagingManager {
    @GuardedBy("mStagedSessions")
    private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();

    @GuardedBy("mStagedSessions")
    private final SparseIntArray mSessionRollbackIds = new SparseIntArray();

    StagingManager(PackageInstallerService pi, ApexManager am, Context context) {
        mPi = pi;
        mApexManager = am;
@@ -166,18 +173,32 @@ public class StagingManager {

    private List<PackageInfo> submitSessionToApexService(
            @NonNull PackageInstallerSession session) throws PackageManagerException {
        final IntArray childSessionsIds = new IntArray();
        final IntArray childSessionIds = new IntArray();
        if (session.isMultiPackage()) {
            for (int id : session.getChildSessionIds()) {
                if (isApexSession(mStagedSessions.get(id))) {
                    childSessionsIds.add(id);
                    childSessionIds.add(id);
                }
            }
        }
        ApexSessionParams apexSessionParams = new ApexSessionParams();
        apexSessionParams.sessionId = session.sessionId;
        apexSessionParams.childSessionIds = childSessionIds.toArray();
        if (session.params.installReason == PackageManager.INSTALL_REASON_ROLLBACK) {
            apexSessionParams.isRollback = true;
            apexSessionParams.rollbackId = retrieveRollbackIdForCommitSession(session.sessionId);
        } else {
            synchronized (mStagedSessions) {
                int rollbackId = mSessionRollbackIds.get(session.sessionId, -1);
                if (rollbackId != -1) {
                    apexSessionParams.hasRollbackEnabled = true;
                    apexSessionParams.rollbackId = rollbackId;
                }
            }
        }
        // submitStagedSession will throw a PackageManagerException if apexd verification fails,
        // which will be propagated to populate stagedSessionErrorMessage of this session.
        final ApexInfoList apexInfoList = mApexManager.submitStagedSession(session.sessionId,
                childSessionsIds.toArray());
        final ApexInfoList apexInfoList = mApexManager.submitStagedSession(apexSessionParams);
        final List<PackageInfo> result = new ArrayList<>();
        for (ApexInfo apexInfo : apexInfoList.apexInfos) {
            final PackageInfo packageInfo;
@@ -208,6 +229,19 @@ public class StagingManager {
        return result;
    }

    private int retrieveRollbackIdForCommitSession(int sessionId) throws PackageManagerException {
        RollbackManager rm = mContext.getSystemService(RollbackManager.class);

        List<RollbackInfo> rollbacks = rm.getRecentlyCommittedRollbacks();
        for (RollbackInfo rollback : rollbacks) {
            if (rollback.getCommittedSessionId() == sessionId) {
                return rollback.getRollbackId();
            }
        }
        throw new PackageManagerException(
                "Could not find rollback id for commit session: " + sessionId);
    }

    private void checkRequiredVersionCode(final PackageInstallerSession session,
            final PackageInfo activePackage) throws PackageManagerException {
        if (session.params.requiredInstalledVersionCode == PackageManager.VERSION_CODE_HIGHEST) {
@@ -633,6 +667,7 @@ public class StagingManager {
    void abortSession(@NonNull PackageInstallerSession session) {
        synchronized (mStagedSessions) {
            mStagedSessions.remove(session.sessionId);
            mSessionRollbackIds.delete(session.sessionId);
        }
    }

@@ -865,6 +900,28 @@ public class StagingManager {
         */
        private void handlePreRebootVerification_Start(@NonNull PackageInstallerSession session) {
            Slog.d(TAG, "Starting preRebootVerification for session " + session.sessionId);

            if ((session.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
                // If rollback is enabled for this session, we call through to the RollbackManager
                // with the list of sessions it must enable rollback for. Note that
                // notifyStagedSession is a synchronous operation.
                final IRollbackManager rm = IRollbackManager.Stub.asInterface(
                        ServiceManager.getService(Context.ROLLBACK_SERVICE));
                try {
                    // NOTE: To stay consistent with the non-staged install flow, we don't fail the
                    // entire install if rollbacks can't be enabled.
                    int rollbackId = rm.notifyStagedSession(session.sessionId);
                    if (rollbackId != -1) {
                        synchronized (mStagedSessions) {
                            mSessionRollbackIds.put(session.sessionId, rollbackId);
                        }
                    }
                } catch (RemoteException re) {
                    Slog.e(TAG, "Failed to notifyStagedSession for session: "
                            + session.sessionId, re);
                }
            }

            notifyPreRebootVerification_Start_Complete(session.sessionId);
        }

@@ -929,25 +986,6 @@ public class StagingManager {
         * </ul></p>
         */
        private void handlePreRebootVerification_End(@NonNull PackageInstallerSession session) {
            if ((session.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
                // If rollback is enabled for this session, we call through to the RollbackManager
                // with the list of sessions it must enable rollback for. Note that
                // notifyStagedSession is a synchronous operation.
                final IRollbackManager rm = IRollbackManager.Stub.asInterface(
                        ServiceManager.getService(Context.ROLLBACK_SERVICE));
                try {
                    // NOTE: To stay consistent with the non-staged install flow, we don't fail the
                    // entire install if rollbacks can't be enabled.
                    if (!rm.notifyStagedSession(session.sessionId)) {
                        Slog.e(TAG, "Unable to enable rollback for session: "
                                + session.sessionId);
                    }
                } catch (RemoteException re) {
                    Slog.e(TAG, "Failed to notifyStagedSession for session: "
                            + session.sessionId, re);
                }
            }

            // Proactively mark session as ready before calling apexd. Although this call order
            // looks counter-intuitive, this is the easiest way to ensure that session won't end up
            // in the inconsistent state:
+3 −1
Original line number Diff line number Diff line
@@ -418,6 +418,7 @@ class Rollback {
                if (isStaged()) {
                    parentParams.setStaged();
                }
                parentParams.setInstallReason(PackageManager.INSTALL_REASON_ROLLBACK);

                int parentSessionId = packageInstaller.createSession(parentParams);
                PackageInstaller.Session parentSession = packageInstaller.openSession(
@@ -484,6 +485,7 @@ class Rollback {
                                synchronized (mLock) {
                                    mState = ROLLBACK_STATE_AVAILABLE;
                                    mRestoreUserDataInProgress = false;
                                    info.setCommittedSessionId(-1);
                                }
                                sendFailure(context, statusReceiver,
                                        RollbackManager.STATUS_FAILURE_INSTALL,
@@ -500,7 +502,6 @@ class Rollback {
                                    mRestoreUserDataInProgress = false;
                                }

                                info.setCommittedSessionId(parentSessionId);
                                info.getCausePackages().addAll(causePackages);
                                RollbackStore.deletePackageCodePaths(this);
                                RollbackStore.saveRollback(this);
@@ -528,6 +529,7 @@ class Rollback {
                );

                mState = ROLLBACK_STATE_COMMITTED;
                info.setCommittedSessionId(parentSessionId);
                mRestoreUserDataInProgress = true;
                parentSession.commit(receiver.getIntentSender());
            } catch (IOException e) {
Loading