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

Commit 71d4206d authored by JW Wang's avatar JW Wang Committed by Android (Google) Code Review
Browse files

Merge changes I5e7bae28,I2a6b58f1,I54b73707

* changes:
  Remove dead code (3/n)
  Unify the flow of enabling rollbacks (2/n)
  Give original session id to non-staged rollbacks (1/n)
parents b734dc1a d845b139
Loading
Loading
Loading
Loading
+1 −8
Original line number Diff line number Diff line
@@ -2539,14 +2539,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {

        mRelinquished = true;

        // TODO(b/169375643): Remove this workaround once b/161121612 is fixed.
        PackageInstaller.SessionParams copiedParams = params.copy();
        if (params.isStaged) {
            // This is called by the pre-reboot verification. Don't enable rollback here since
            // it has been enabled when pre-reboot verification starts.
            copiedParams.installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
        }
        return mPm.new VerificationParams(user, stageDir, localObserver, copiedParams,
        return mPm.new VerificationParams(user, stageDir, localObserver, params,
                mInstallSource, mInstallerUid, mSigningDetails, sessionId, mPackageLite);
    }

+15 −40
Original line number Diff line number Diff line
@@ -116,10 +116,10 @@ class Rollback {
    static final int ROLLBACK_STATE_DELETED = 4;

    /**
     * The session ID for the staged session if this rollback data represents a staged session,
     * {@code -1} otherwise.
     * The session ID associate with this rollback. This is the parent session ID in the case of
     * a multi-package session.
     */
    private final int mStagedSessionId;
    private final int mOriginalSessionId;

    /**
     * The rollback info for this rollback.
@@ -180,13 +180,6 @@ class Rollback {
     */
    private final int[] mPackageSessionIds;

    /**
     * The number of sessions in the install which are notified with success by
     * {@link PackageInstaller.SessionCallback#onFinished(int, boolean)}.
     * This rollback will be enabled only after all child sessions finished with success.
     */
    private int mNumPackageSessionsWithSuccess;

    /**
     * The extension versions supported at the time of rollback creation.
     */
@@ -203,24 +196,25 @@ class Rollback {
     *
     * @param rollbackId the id of the rollback.
     * @param backupDir the directory where the rollback data is stored.
     * @param stagedSessionId the session id if this is a staged rollback, -1 otherwise.
     * @param originalSessionId the session id associated with this rollback.
     * @param isStaged true if this is a staged rollback.
     * @param userId the user that performed the install with rollback enabled.
     * @param installerPackageName the installer package name from the original install session.
     * @param packageSessionIds the session ids for all packages in the install.
     * @param extensionVersions the extension versions supported at the time of rollback creation
     */
    Rollback(int rollbackId, File backupDir, int stagedSessionId, int userId,
    Rollback(int rollbackId, File backupDir, int originalSessionId, boolean isStaged, int userId,
            String installerPackageName, int[] packageSessionIds,
            SparseIntArray extensionVersions) {
        this.info = new RollbackInfo(rollbackId,
                /* packages */ new ArrayList<>(),
                /* isStaged */ stagedSessionId != -1,
                /* isStaged */ isStaged,
                /* causePackages */ new ArrayList<>(),
                /* committedSessionId */ -1);
        mUserId = userId;
        mInstallerPackageName = installerPackageName;
        mBackupDir = backupDir;
        mStagedSessionId = stagedSessionId;
        mOriginalSessionId = originalSessionId;
        mState = ROLLBACK_STATE_ENABLING;
        mTimestamp = Instant.now();
        mPackageSessionIds = packageSessionIds != null ? packageSessionIds : new int[0];
@@ -228,16 +222,10 @@ class Rollback {
        mHandler = Looper.myLooper() != null ? new Handler(Looper.myLooper()) : null;
    }

    Rollback(int rollbackId, File backupDir, int stagedSessionId, int userId,
             String installerPackageName) {
        this(rollbackId, backupDir, stagedSessionId, userId, installerPackageName, null,
                new SparseIntArray(0));
    }

    /**
     * Constructs a pre-populated Rollback instance.
     */
    Rollback(RollbackInfo info, File backupDir, Instant timestamp, int stagedSessionId,
    Rollback(RollbackInfo info, File backupDir, Instant timestamp, int originalSessionId,
            @RollbackState int state, String stateDescription, boolean restoreUserDataInProgress,
            int userId, String installerPackageName, SparseIntArray extensionVersions) {
        this.info = info;
@@ -245,7 +233,7 @@ class Rollback {
        mInstallerPackageName = installerPackageName;
        mBackupDir = backupDir;
        mTimestamp = timestamp;
        mStagedSessionId = stagedSessionId;
        mOriginalSessionId = originalSessionId;
        mState = state;
        mStateDescription = stateDescription;
        mRestoreUserDataInProgress = restoreUserDataInProgress;
@@ -298,12 +286,11 @@ class Rollback {
    }

    /**
     * Returns the session ID for the staged session if this rollback data represents a staged
     * session, or {@code -1} otherwise.
     * Returns the session ID associated with this rollback, or {@code -1} if unknown.
     */
    @AnyThread
    int getStagedSessionId() {
        return mStagedSessionId;
    int getOriginalSessionId() {
        return mOriginalSessionId;
    }

    /**
@@ -837,17 +824,6 @@ class Rollback {
        return false;
    }

    /**
     * Called when a child session finished with success.
     * Returns true when all child sessions are notified with success. This rollback will be
     * enabled only after all child sessions finished with success.
     */
    @WorkerThread
    boolean notifySessionWithSuccess() {
        assertInWorkerThread();
        return ++mNumPackageSessionsWithSuccess == mPackageSessionIds.length;
    }

    /**
     * Returns true if all packages in this rollback are enabled. We won't enable this rollback
     * until all packages are enabled. Note we don't count apk-in-apex here since they are enabled
@@ -954,9 +930,8 @@ class Rollback {
        ipw.println("-state: " + getStateAsString());
        ipw.println("-stateDescription: " + mStateDescription);
        ipw.println("-timestamp: " + getTimestamp());
        if (getStagedSessionId() != -1) {
            ipw.println("-stagedSessionId: " + getStagedSessionId());
        }
        ipw.println("-isStaged: " + isStaged());
        ipw.println("-originalSessionId: " + getOriginalSessionId());
        ipw.println("-packages:");
        ipw.increaseIndent();
        for (PackageRollbackInfo pkg : info.getPackages()) {
+28 −51
Original line number Diff line number Diff line
@@ -611,11 +611,11 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba
                }

                PackageInstaller.SessionInfo session = mContext.getPackageManager()
                        .getPackageInstaller().getSessionInfo(rollback.getStagedSessionId());
                        .getPackageInstaller().getSessionInfo(rollback.getOriginalSessionId());
                if (session == null || session.isStagedSessionFailed()) {
                    if (rollback.isEnabling()) {
                        iter.remove();
                        deleteRollback(rollback, "Session " + rollback.getStagedSessionId()
                        deleteRollback(rollback, "Session " + rollback.getOriginalSessionId()
                                + " not existed or failed");
                    }
                    continue;
@@ -789,7 +789,13 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba
            newRollback = createNewRollback(parentSession);
        }

        return enableRollbackForPackageSession(newRollback, packageSession);
        if (enableRollbackForPackageSession(newRollback, packageSession)) {
            // Persist the rollback if all packages are enabled. We will make the rollback
            // available once the whole session is installed successfully.
            return newRollback.allPackagesEnabled() ? completeEnableRollback(newRollback) : true;
        } else {
            return false;
        }
    }

    @WorkerThread
@@ -978,43 +984,10 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba
            throw new SecurityException("notifyStagedSession may only be called by the system.");
        }

        // NOTE: We post this runnable on the RollbackManager's binder thread because we'd prefer
        // to preserve the invariant that all operations that modify state happen there.
        return awaitResult(() -> {
            assertInWorkerThread();
            PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();

            final PackageInstaller.SessionInfo session = installer.getSessionInfo(sessionId);
            if (session == null) {
                Slog.e(TAG, "No matching install session for: " + sessionId);
                return -1;
            }

            Rollback newRollback = createNewRollback(session);
            if (!session.isMultiPackage()) {
                if (!enableRollbackForPackageSession(newRollback, session)) {
                    Slog.e(TAG, "Unable to enable rollback for session: " + sessionId);
                }
            } else {
                for (int childSessionId : session.getChildSessionIds()) {
                    final PackageInstaller.SessionInfo childSession =
                            installer.getSessionInfo(childSessionId);
                    if (childSession == null) {
                        Slog.e(TAG, "No matching child install session for: " + childSessionId);
                        break;
                    }
                    if (!enableRollbackForPackageSession(newRollback, childSession)) {
                        Slog.e(TAG, "Unable to enable rollback for session: " + sessionId);
                        break;
                    }
                }
            }

            if (!completeEnableRollback(newRollback)) {
                return -1;
            } else {
                return newRollback.info.getRollbackId();
            }
            Rollback rollback = getRollbackForSession(sessionId);
            return rollback != null ? rollback.info.getRollbackId() : -1;
        });
    }

@@ -1124,16 +1097,21 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba
                Slog.v(TAG, "SessionCallback.onFinished id=" + sessionId + " success=" + success);
            }

            if (success) {
            Rollback rollback = getRollbackForSession(sessionId);
                if (rollback != null && !rollback.isStaged() && rollback.isEnabling()
                        && rollback.notifySessionWithSuccess()
                        && completeEnableRollback(rollback)) {
            if (rollback == null || !rollback.isEnabling()
                    || sessionId != rollback.getOriginalSessionId()) {
                // We only care about the parent session id which will tell us whether the
                // whole session is successful or not.
                return;
            }
            if (success) {
                if (!rollback.isStaged() && completeEnableRollback(rollback)) {
                    // completeEnableRollback() ensures the rollback is deleted if not all packages
                    // are enabled. For staged rollbacks, we will make them available in
                    // onBootCompleted().
                    makeRollbackAvailable(rollback);
                }
            } else {
                Rollback rollback = getRollbackForSession(sessionId);
                if (rollback != null && rollback.isEnabling()) {
                Slog.w(TAG, "Delete rollback id=" + rollback.info.getRollbackId()
                        + " for failed session id=" + sessionId);
                mRollbacks.remove(rollback);
@@ -1141,7 +1119,6 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba
            }
        }
    }
    }

    /**
     * Persist a rollback as enable-completed. It does not make the rollback available yet.
@@ -1307,7 +1284,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba
            rollback = mRollbackStore.createStagedRollback(rollbackId, parentSessionId, userId,
                    installerPackageName, packageSessionIds, getExtensionVersions());
        } else {
            rollback = mRollbackStore.createNonStagedRollback(rollbackId, userId,
            rollback = mRollbackStore.createNonStagedRollback(rollbackId, parentSessionId, userId,
                    installerPackageName, packageSessionIds, getExtensionVersions());
        }

@@ -1339,7 +1316,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub implements Rollba
        // We expect mRollbacks to be a very small list; linear search should be plenty fast.
        for (int i = 0; i < mRollbacks.size(); ++i) {
            Rollback rollback = mRollbacks.get(i);
            if (rollback.getStagedSessionId() == sessionId
            if (rollback.getOriginalSessionId() == sessionId
                    || rollback.containsSessionId(sessionId)) {
                return rollback;
            }
+12 −9
Original line number Diff line number Diff line
@@ -209,23 +209,24 @@ class RollbackStore {
     * Creates a new Rollback instance for a non-staged rollback with
     * backupDir assigned.
     */
    Rollback createNonStagedRollback(int rollbackId, int userId, String installerPackageName,
            int[] packageSessionIds, SparseIntArray extensionVersions) {
    Rollback createNonStagedRollback(int rollbackId, int originalSessionId, int userId,
            String installerPackageName, int[] packageSessionIds,
            SparseIntArray extensionVersions) {
        File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId));
        return new Rollback(rollbackId, backupDir, -1, userId, installerPackageName,
                packageSessionIds, extensionVersions);
        return new Rollback(rollbackId, backupDir, originalSessionId, /* isStaged */ false, userId,
                installerPackageName, packageSessionIds, extensionVersions);
    }

    /**
     * Creates a new Rollback instance for a staged rollback with
     * backupDir assigned.
     */
    Rollback createStagedRollback(int rollbackId, int stagedSessionId, int userId,
    Rollback createStagedRollback(int rollbackId, int originalSessionId, int userId,
            String installerPackageName, int[] packageSessionIds,
            SparseIntArray extensionVersions) {
        File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId));
        return new Rollback(rollbackId, backupDir, stagedSessionId, userId, installerPackageName,
                packageSessionIds, extensionVersions);
        return new Rollback(rollbackId, backupDir, originalSessionId, /* isStaged */ true, userId,
                installerPackageName, packageSessionIds, extensionVersions);
    }

    private static boolean isLinkPossible(File oldFile, File newFile) {
@@ -312,7 +313,7 @@ class RollbackStore {
            JSONObject dataJson = new JSONObject();
            dataJson.put("info", rollbackInfoToJson(rollback.info));
            dataJson.put("timestamp", rollback.getTimestamp().toString());
            dataJson.put("stagedSessionId", rollback.getStagedSessionId());
            dataJson.put("originalSessionId", rollback.getOriginalSessionId());
            dataJson.put("state", rollback.getStateAsString());
            dataJson.put("stateDescription", rollback.getStateDescription());
            dataJson.put("restoreUserDataInProgress", rollback.isRestoreUserDataInProgress());
@@ -380,7 +381,9 @@ class RollbackStore {
                rollbackInfoFromJson(dataJson.getJSONObject("info")),
                backupDir,
                Instant.parse(dataJson.getString("timestamp")),
                dataJson.getInt("stagedSessionId"),
                // Backward compatibility: Historical rollbacks are not erased upon OTA update.
                //  Need to load the old field 'stagedSessionId' as fallback.
                dataJson.optInt("originalSessionId", dataJson.optInt("stagedSessionId", -1)),
                rollbackStateFromString(dataJson.getString("state")),
                dataJson.optString("stateDescription"),
                dataJson.getBoolean("restoreUserDataInProgress"),
+4 −2
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import static org.mockito.MockitoAnnotations.initMocks;
import android.content.pm.VersionedPackage;
import android.content.rollback.PackageRollbackInfo;
import android.content.rollback.PackageRollbackInfo.RestoreInfo;
import android.util.SparseIntArray;

import com.android.server.pm.ApexManager;
import com.android.server.pm.Installer;
@@ -119,8 +120,9 @@ public class AppDataRollbackHelperTest {
    }

    private static Rollback createRollbackForId(int rollbackId) {
        return new Rollback(rollbackId, new File("/does/not/exist"), -1,
                0, "com.xyz");
        return new Rollback(rollbackId, new File("/does/not/exist"), -1, /* isStaged */ false, 0,
                "com.xyz", null, new SparseIntArray(0));

    }

    @Test
Loading