Loading services/core/java/com/android/server/rollback/Rollback.java +113 −19 Original line number Diff line number Diff line Loading @@ -65,7 +65,7 @@ class Rollback { /** * The directory where the rollback data is stored. */ public final File backupDir; private final File mBackupDir; /** * The time when the upgrade occurred, for purposes of expiring Loading @@ -74,24 +74,24 @@ class Rollback { * The timestamp is not applicable for all rollback states, but we make * sure to keep it non-null to avoid potential errors there. */ public @NonNull Instant timestamp; private @NonNull Instant mTimestamp; /** * The session ID for the staged session if this rollback data represents a staged session, * {@code -1} otherwise. */ public final int stagedSessionId; private final int mStagedSessionId; /** * The current state of the rollback. * ENABLING, AVAILABLE, or COMMITTED. */ public @RollbackState int state; private @RollbackState int mState; /** * The id of the post-reboot apk session for a staged install, if any. */ public int apkSessionId = -1; private int mApkSessionId = -1; /** * True if we are expecting the package manager to call restoreUserData Loading @@ -99,7 +99,7 @@ class Rollback { * has not yet been fully applied. */ // NOTE: All accesses to this field are from the RollbackManager handler thread. public boolean restoreUserDataInProgress = false; private boolean mRestoreUserDataInProgress = false; /** * Constructs a new, empty Rollback instance. Loading @@ -114,10 +114,10 @@ class Rollback { /* isStaged */ stagedSessionId != -1, /* causePackages */ new ArrayList<>(), /* committedSessionId */ -1); this.backupDir = backupDir; this.stagedSessionId = stagedSessionId; this.state = ROLLBACK_STATE_ENABLING; this.timestamp = Instant.now(); mBackupDir = backupDir; mStagedSessionId = stagedSessionId; mState = ROLLBACK_STATE_ENABLING; mTimestamp = Instant.now(); } /** Loading @@ -126,21 +126,115 @@ class Rollback { Rollback(RollbackInfo info, File backupDir, Instant timestamp, int stagedSessionId, @RollbackState int state, int apkSessionId, boolean restoreUserDataInProgress) { this.info = info; this.backupDir = backupDir; this.timestamp = timestamp; this.stagedSessionId = stagedSessionId; this.state = state; this.apkSessionId = apkSessionId; this.restoreUserDataInProgress = restoreUserDataInProgress; mBackupDir = backupDir; mTimestamp = timestamp; mStagedSessionId = stagedSessionId; mState = state; mApkSessionId = apkSessionId; mRestoreUserDataInProgress = restoreUserDataInProgress; } /** * Whether the rollback is for rollback of a staged install. */ public boolean isStaged() { boolean isStaged() { return info.isStaged(); } /** * Returns the directory in which rollback data should be stored. */ File getBackupDir() { return mBackupDir; } /** * Returns the time when the upgrade occurred, for purposes of expiring rollback data. */ Instant getTimestamp() { return mTimestamp; } /** * Sets the time at which upgrade occurred. */ void setTimestamp(Instant timestamp) { mTimestamp = timestamp; } /** * Returns the session ID for the staged session if this rollback data represents a staged * session, or {@code -1} otherwise. */ int getStagedSessionId() { return mStagedSessionId; } /** * Returns true if the rollback is in the ENABLING state. */ boolean isEnabling() { return mState == ROLLBACK_STATE_ENABLING; } /** * Returns true if the rollback is in the AVAILABLE state. */ boolean isAvailable() { return mState == ROLLBACK_STATE_AVAILABLE; } /** * Returns true if the rollback is in the COMMITTED state. */ boolean isCommitted() { return mState == ROLLBACK_STATE_COMMITTED; } /** * Sets the state of the rollback to AVAILABLE. */ void setAvailable() { mState = ROLLBACK_STATE_AVAILABLE; } /** * Sets the state of the rollback to COMMITTED. */ void setCommitted() { mState = ROLLBACK_STATE_COMMITTED; } /** * Returns the id of the post-reboot apk session for a staged install, if any. */ int getApkSessionId() { return mApkSessionId; } /** * Sets the id of the post-reboot apk session for a staged install. */ void setApkSessionId(int apkSessionId) { mApkSessionId = apkSessionId; } /** * Returns true if we are expecting the package manager to call restoreUserData for this * rollback because it has just been committed but the rollback has not yet been fully applied. */ boolean isRestoreUserDataInProgress() { return mRestoreUserDataInProgress; } /** * Sets whether we are expecting the package manager to call restoreUserData for this * rollback because it has just been committed but the rollback has not yet been fully applied. */ void setRestoreUserDataInProgress(boolean restoreUserDataInProgress) { mRestoreUserDataInProgress = restoreUserDataInProgress; } static String rollbackStateToString(@RollbackState int state) { switch (state) { case Rollback.ROLLBACK_STATE_ENABLING: return "enabling"; Loading @@ -160,7 +254,7 @@ class Rollback { throw new ParseException("Invalid rollback state: " + state, 0); } public String getStateAsString() { return rollbackStateToString(state); String getStateAsString() { return rollbackStateToString(mState); } } services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +33 −33 Original line number Diff line number Diff line Loading @@ -282,7 +282,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { List<RollbackInfo> rollbacks = new ArrayList<>(); for (int i = 0; i < mRollbacks.size(); ++i) { Rollback rollback = mRollbacks.get(i); if (rollback.state == Rollback.ROLLBACK_STATE_AVAILABLE) { if (rollback.isAvailable()) { rollbacks.add(rollback.info); } } Loading @@ -298,7 +298,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { List<RollbackInfo> rollbacks = new ArrayList<>(); for (int i = 0; i < mRollbacks.size(); ++i) { Rollback rollback = mRollbacks.get(i); if (rollback.state == Rollback.ROLLBACK_STATE_COMMITTED) { if (rollback.isCommitted()) { rollbacks.add(rollback.info); } } Loading Loading @@ -332,7 +332,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { Iterator<Rollback> iter = mRollbacks.iterator(); while (iter.hasNext()) { Rollback rollback = iter.next(); rollback.timestamp = rollback.timestamp.plusMillis(timeDifference); rollback.setTimestamp(rollback.getTimestamp().plusMillis(timeDifference)); saveRollback(rollback); } } Loading @@ -358,7 +358,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { Slog.i(TAG, "Initiating rollback"); Rollback rollback = getRollbackForId(rollbackId); if (rollback == null || rollback.state != Rollback.ROLLBACK_STATE_AVAILABLE) { if (rollback == null || !rollback.isAvailable()) { sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE_ROLLBACK_UNAVAILABLE, "Rollback unavailable"); return; Loading Loading @@ -454,8 +454,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // TODO: Could this cause a rollback to be // resurrected if it should otherwise have // expired by now? rollback.state = Rollback.ROLLBACK_STATE_AVAILABLE; rollback.restoreUserDataInProgress = false; rollback.setAvailable(); rollback.setRestoreUserDataInProgress(false); } sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE_INSTALL, "Rollback downgrade install failed: " Loading @@ -468,7 +468,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { if (!rollback.isStaged()) { // All calls to restoreUserData should have // completed by now for a non-staged install. rollback.restoreUserDataInProgress = false; rollback.setRestoreUserDataInProgress(false); } rollback.info.setCommittedSessionId(parentSessionId); Loading @@ -490,8 +490,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { ); synchronized (mLock) { rollback.state = Rollback.ROLLBACK_STATE_COMMITTED; rollback.restoreUserDataInProgress = true; rollback.setCommitted(); rollback.setRestoreUserDataInProgress(true); } parentSession.commit(receiver.getIntentSender()); } catch (IOException e) { Loading Loading @@ -618,9 +618,9 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { synchronized (mLock) { for (Rollback rollback : mRollbacks) { if (rollback.isStaged()) { if (rollback.state == Rollback.ROLLBACK_STATE_ENABLING) { if (rollback.isEnabling()) { enabling.add(rollback); } else if (rollback.restoreUserDataInProgress) { } else if (rollback.isRestoreUserDataInProgress()) { restoreInProgress.add(rollback); } Loading @@ -635,8 +635,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { for (Rollback rollback : enabling) { PackageInstaller installer = mContext.getPackageManager().getPackageInstaller(); PackageInstaller.SessionInfo session = installer.getSessionInfo( rollback.stagedSessionId); PackageInstaller.SessionInfo session = installer.getSessionInfo(rollback.getStagedSessionId()); if (session == null || session.isStagedSessionFailed()) { // TODO: Do we need to remove this from // mRollbacks, or is it okay to leave as Loading @@ -650,13 +650,13 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { for (Rollback rollback : restoreInProgress) { PackageInstaller installer = mContext.getPackageManager().getPackageInstaller(); PackageInstaller.SessionInfo session = installer.getSessionInfo( rollback.stagedSessionId); PackageInstaller.SessionInfo session = installer.getSessionInfo(rollback.getStagedSessionId()); // TODO: What if session is null? if (session != null) { if (session.isStagedSessionApplied() || session.isStagedSessionFailed()) { synchronized (mLock) { rollback.restoreUserDataInProgress = false; rollback.setRestoreUserDataInProgress(false); } saveRollback(rollback); } Loading Loading @@ -694,8 +694,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { while (iter.hasNext()) { Rollback rollback = iter.next(); // TODO: Should we remove rollbacks in the ENABLING state here? if (rollback.state == Rollback.ROLLBACK_STATE_AVAILABLE || rollback.state == Rollback.ROLLBACK_STATE_ENABLING) { if (rollback.isEnabling() || rollback.isAvailable()) { for (PackageRollbackInfo info : rollback.info.getPackages()) { if (info.getPackageName().equals(packageName) && !packageVersionsEqual( Loading Loading @@ -761,15 +760,16 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { Iterator<Rollback> iter = mRollbacks.iterator(); while (iter.hasNext()) { Rollback rollback = iter.next(); if (rollback.state != Rollback.ROLLBACK_STATE_AVAILABLE) { if (!rollback.isAvailable()) { continue; } if (!now.isBefore( rollback.timestamp.plusMillis(mRollbackLifetimeDurationInMillis))) { rollback.getTimestamp() .plusMillis(mRollbackLifetimeDurationInMillis))) { iter.remove(); deleteRollback(rollback); } else if (oldest == null || oldest.isAfter(rollback.timestamp)) { oldest = rollback.timestamp; } else if (oldest == null || oldest.isAfter(rollback.getTimestamp())) { oldest = rollback.getTimestamp(); } } } Loading Loading @@ -877,7 +877,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { synchronized (mLock) { for (int i = 0; i < mRollbacks.size(); ++i) { Rollback rollback = mRollbacks.get(i); if (rollback.apkSessionId == parentSession.getSessionId()) { if (rollback.getApkSessionId() == parentSession.getSessionId()) { // This is the apk session for a staged session with rollback enabled. We do not // need to create a new rollback for this session. return true; Loading Loading @@ -1020,7 +1020,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // staged installs for (int i = 0; i < mRollbacks.size(); i++) { Rollback rollback = mRollbacks.get(i); if (rollback.state != Rollback.ROLLBACK_STATE_ENABLING) { if (!rollback.isEnabling()) { continue; } Loading Loading @@ -1053,7 +1053,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { synchronized (mLock) { for (int i = 0; i < mRollbacks.size(); ++i) { Rollback candidate = mRollbacks.get(i); if (candidate.restoreUserDataInProgress) { if (candidate.isRestoreUserDataInProgress()) { info = getPackageRollbackInfo(candidate, packageName); if (info != null) { rollback = candidate; Loading Loading @@ -1146,8 +1146,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { synchronized (mLock) { for (int i = 0; i < mRollbacks.size(); ++i) { Rollback candidate = mRollbacks.get(i); if (candidate.stagedSessionId == originalSessionId) { candidate.apkSessionId = apkSessionId; if (candidate.getStagedSessionId() == originalSessionId) { candidate.setApkSessionId(apkSessionId); rollback = candidate; break; } Loading Loading @@ -1333,8 +1333,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // to a new package being installed. Won't this revive an expired // rollback? Consider adding a ROLLBACK_STATE_EXPIRED to address this. synchronized (mLock) { rollback.state = Rollback.ROLLBACK_STATE_AVAILABLE; rollback.timestamp = Instant.now(); rollback.setAvailable(); rollback.setTimestamp(Instant.now()); } saveRollback(rollback); Loading Loading @@ -1434,9 +1434,9 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { ipw.println(info.getRollbackId() + ":"); ipw.increaseIndent(); ipw.println("-state: " + rollback.getStateAsString()); ipw.println("-timestamp: " + rollback.timestamp); if (rollback.stagedSessionId != -1) { ipw.println("-stagedSessionId: " + rollback.stagedSessionId); ipw.println("-timestamp: " + rollback.getTimestamp()); if (rollback.getStagedSessionId() != -1) { ipw.println("-stagedSessionId: " + rollback.getStagedSessionId()); } ipw.println("-packages:"); ipw.increaseIndent(); Loading @@ -1446,7 +1446,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { + " -> " + pkg.getVersionRolledBackTo().getLongVersionCode()); } ipw.decreaseIndent(); if (rollback.state == Rollback.ROLLBACK_STATE_COMMITTED) { if (rollback.isCommitted()) { ipw.println("-causePackages:"); ipw.increaseIndent(); for (VersionedPackage cPkg : info.getCausePackages()) { Loading services/core/java/com/android/server/rollback/RollbackStore.java +10 −11 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package com.android.server.rollback; import static com.android.server.rollback.Rollback.rollbackStateFromString; import static com.android.server.rollback.Rollback.rollbackStateToString; import android.annotation.NonNull; import android.content.pm.VersionedPackage; Loading Loading @@ -216,7 +215,7 @@ class RollbackStore { static void backupPackageCodePath(Rollback rollback, String packageName, String codePath) throws IOException { File sourceFile = new File(codePath); File targetDir = new File(rollback.backupDir, packageName); File targetDir = new File(rollback.getBackupDir(), packageName); targetDir.mkdirs(); File targetFile = new File(targetDir, sourceFile.getName()); Loading @@ -229,7 +228,7 @@ class RollbackStore { * Includes the base apk and any splits. Returns null if none found. */ static File[] getPackageCodePaths(Rollback rollback, String packageName) { File targetDir = new File(rollback.backupDir, packageName); File targetDir = new File(rollback.getBackupDir(), packageName); File[] files = targetDir.listFiles(); if (files == null || files.length == 0) { return null; Loading @@ -243,7 +242,7 @@ class RollbackStore { */ static void deletePackageCodePaths(Rollback rollback) { for (PackageRollbackInfo info : rollback.info.getPackages()) { File targetDir = new File(rollback.backupDir, info.getPackageName()); File targetDir = new File(rollback.getBackupDir(), info.getPackageName()); removeFile(targetDir); } } Loading @@ -255,13 +254,13 @@ class RollbackStore { try { JSONObject dataJson = new JSONObject(); dataJson.put("info", rollbackInfoToJson(rollback.info)); dataJson.put("timestamp", rollback.timestamp.toString()); dataJson.put("stagedSessionId", rollback.stagedSessionId); dataJson.put("state", rollbackStateToString(rollback.state)); dataJson.put("apkSessionId", rollback.apkSessionId); dataJson.put("restoreUserDataInProgress", rollback.restoreUserDataInProgress); dataJson.put("timestamp", rollback.getTimestamp().toString()); dataJson.put("stagedSessionId", rollback.getStagedSessionId()); dataJson.put("state", rollback.getStateAsString()); dataJson.put("apkSessionId", rollback.getApkSessionId()); dataJson.put("restoreUserDataInProgress", rollback.isRestoreUserDataInProgress()); PrintWriter pw = new PrintWriter(new File(rollback.backupDir, "rollback.json")); PrintWriter pw = new PrintWriter(new File(rollback.getBackupDir(), "rollback.json")); pw.println(dataJson.toString()); pw.close(); } catch (JSONException e) { Loading @@ -273,7 +272,7 @@ class RollbackStore { * Removes all persistent storage associated with the given rollback. */ void deleteRollback(Rollback rollback) { removeFile(rollback.backupDir); removeFile(rollback.getBackupDir()); } /** Loading services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java 0 → 100644 +77 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.rollback; import static com.google.common.truth.Truth.assertThat; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.io.File; @RunWith(JUnit4.class) public class RollbackUnitTest { @Test public void newEmptyStagedRollbackDefaults() { int rollbackId = 123; int sessionId = 567; File file = new File("/test/testing"); Rollback rollback = new Rollback(rollbackId, file, sessionId); assertThat(rollback.isEnabling()).isTrue(); assertThat(rollback.getBackupDir().getAbsolutePath()).isEqualTo("/test/testing"); assertThat(rollback.isStaged()).isTrue(); assertThat(rollback.getStagedSessionId()).isEqualTo(567); } @Test public void newEmptyNonStagedRollbackDefaults() { int rollbackId = 123; File file = new File("/test/testing"); Rollback rollback = new Rollback(rollbackId, file, -1); assertThat(rollback.isEnabling()).isTrue(); assertThat(rollback.getBackupDir().getAbsolutePath()).isEqualTo("/test/testing"); assertThat(rollback.isStaged()).isFalse(); } @Test public void rollbackStateChanges() { Rollback rollback = new Rollback(123, new File("/test/testing"), -1); assertThat(rollback.isEnabling()).isTrue(); assertThat(rollback.isAvailable()).isFalse(); assertThat(rollback.isCommitted()).isFalse(); rollback.setAvailable(); assertThat(rollback.isEnabling()).isFalse(); assertThat(rollback.isAvailable()).isTrue(); assertThat(rollback.isCommitted()).isFalse(); rollback.setCommitted(); assertThat(rollback.isEnabling()).isFalse(); assertThat(rollback.isAvailable()).isFalse(); assertThat(rollback.isCommitted()).isTrue(); } } Loading
services/core/java/com/android/server/rollback/Rollback.java +113 −19 Original line number Diff line number Diff line Loading @@ -65,7 +65,7 @@ class Rollback { /** * The directory where the rollback data is stored. */ public final File backupDir; private final File mBackupDir; /** * The time when the upgrade occurred, for purposes of expiring Loading @@ -74,24 +74,24 @@ class Rollback { * The timestamp is not applicable for all rollback states, but we make * sure to keep it non-null to avoid potential errors there. */ public @NonNull Instant timestamp; private @NonNull Instant mTimestamp; /** * The session ID for the staged session if this rollback data represents a staged session, * {@code -1} otherwise. */ public final int stagedSessionId; private final int mStagedSessionId; /** * The current state of the rollback. * ENABLING, AVAILABLE, or COMMITTED. */ public @RollbackState int state; private @RollbackState int mState; /** * The id of the post-reboot apk session for a staged install, if any. */ public int apkSessionId = -1; private int mApkSessionId = -1; /** * True if we are expecting the package manager to call restoreUserData Loading @@ -99,7 +99,7 @@ class Rollback { * has not yet been fully applied. */ // NOTE: All accesses to this field are from the RollbackManager handler thread. public boolean restoreUserDataInProgress = false; private boolean mRestoreUserDataInProgress = false; /** * Constructs a new, empty Rollback instance. Loading @@ -114,10 +114,10 @@ class Rollback { /* isStaged */ stagedSessionId != -1, /* causePackages */ new ArrayList<>(), /* committedSessionId */ -1); this.backupDir = backupDir; this.stagedSessionId = stagedSessionId; this.state = ROLLBACK_STATE_ENABLING; this.timestamp = Instant.now(); mBackupDir = backupDir; mStagedSessionId = stagedSessionId; mState = ROLLBACK_STATE_ENABLING; mTimestamp = Instant.now(); } /** Loading @@ -126,21 +126,115 @@ class Rollback { Rollback(RollbackInfo info, File backupDir, Instant timestamp, int stagedSessionId, @RollbackState int state, int apkSessionId, boolean restoreUserDataInProgress) { this.info = info; this.backupDir = backupDir; this.timestamp = timestamp; this.stagedSessionId = stagedSessionId; this.state = state; this.apkSessionId = apkSessionId; this.restoreUserDataInProgress = restoreUserDataInProgress; mBackupDir = backupDir; mTimestamp = timestamp; mStagedSessionId = stagedSessionId; mState = state; mApkSessionId = apkSessionId; mRestoreUserDataInProgress = restoreUserDataInProgress; } /** * Whether the rollback is for rollback of a staged install. */ public boolean isStaged() { boolean isStaged() { return info.isStaged(); } /** * Returns the directory in which rollback data should be stored. */ File getBackupDir() { return mBackupDir; } /** * Returns the time when the upgrade occurred, for purposes of expiring rollback data. */ Instant getTimestamp() { return mTimestamp; } /** * Sets the time at which upgrade occurred. */ void setTimestamp(Instant timestamp) { mTimestamp = timestamp; } /** * Returns the session ID for the staged session if this rollback data represents a staged * session, or {@code -1} otherwise. */ int getStagedSessionId() { return mStagedSessionId; } /** * Returns true if the rollback is in the ENABLING state. */ boolean isEnabling() { return mState == ROLLBACK_STATE_ENABLING; } /** * Returns true if the rollback is in the AVAILABLE state. */ boolean isAvailable() { return mState == ROLLBACK_STATE_AVAILABLE; } /** * Returns true if the rollback is in the COMMITTED state. */ boolean isCommitted() { return mState == ROLLBACK_STATE_COMMITTED; } /** * Sets the state of the rollback to AVAILABLE. */ void setAvailable() { mState = ROLLBACK_STATE_AVAILABLE; } /** * Sets the state of the rollback to COMMITTED. */ void setCommitted() { mState = ROLLBACK_STATE_COMMITTED; } /** * Returns the id of the post-reboot apk session for a staged install, if any. */ int getApkSessionId() { return mApkSessionId; } /** * Sets the id of the post-reboot apk session for a staged install. */ void setApkSessionId(int apkSessionId) { mApkSessionId = apkSessionId; } /** * Returns true if we are expecting the package manager to call restoreUserData for this * rollback because it has just been committed but the rollback has not yet been fully applied. */ boolean isRestoreUserDataInProgress() { return mRestoreUserDataInProgress; } /** * Sets whether we are expecting the package manager to call restoreUserData for this * rollback because it has just been committed but the rollback has not yet been fully applied. */ void setRestoreUserDataInProgress(boolean restoreUserDataInProgress) { mRestoreUserDataInProgress = restoreUserDataInProgress; } static String rollbackStateToString(@RollbackState int state) { switch (state) { case Rollback.ROLLBACK_STATE_ENABLING: return "enabling"; Loading @@ -160,7 +254,7 @@ class Rollback { throw new ParseException("Invalid rollback state: " + state, 0); } public String getStateAsString() { return rollbackStateToString(state); String getStateAsString() { return rollbackStateToString(mState); } }
services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +33 −33 Original line number Diff line number Diff line Loading @@ -282,7 +282,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { List<RollbackInfo> rollbacks = new ArrayList<>(); for (int i = 0; i < mRollbacks.size(); ++i) { Rollback rollback = mRollbacks.get(i); if (rollback.state == Rollback.ROLLBACK_STATE_AVAILABLE) { if (rollback.isAvailable()) { rollbacks.add(rollback.info); } } Loading @@ -298,7 +298,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { List<RollbackInfo> rollbacks = new ArrayList<>(); for (int i = 0; i < mRollbacks.size(); ++i) { Rollback rollback = mRollbacks.get(i); if (rollback.state == Rollback.ROLLBACK_STATE_COMMITTED) { if (rollback.isCommitted()) { rollbacks.add(rollback.info); } } Loading Loading @@ -332,7 +332,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { Iterator<Rollback> iter = mRollbacks.iterator(); while (iter.hasNext()) { Rollback rollback = iter.next(); rollback.timestamp = rollback.timestamp.plusMillis(timeDifference); rollback.setTimestamp(rollback.getTimestamp().plusMillis(timeDifference)); saveRollback(rollback); } } Loading @@ -358,7 +358,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { Slog.i(TAG, "Initiating rollback"); Rollback rollback = getRollbackForId(rollbackId); if (rollback == null || rollback.state != Rollback.ROLLBACK_STATE_AVAILABLE) { if (rollback == null || !rollback.isAvailable()) { sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE_ROLLBACK_UNAVAILABLE, "Rollback unavailable"); return; Loading Loading @@ -454,8 +454,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // TODO: Could this cause a rollback to be // resurrected if it should otherwise have // expired by now? rollback.state = Rollback.ROLLBACK_STATE_AVAILABLE; rollback.restoreUserDataInProgress = false; rollback.setAvailable(); rollback.setRestoreUserDataInProgress(false); } sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE_INSTALL, "Rollback downgrade install failed: " Loading @@ -468,7 +468,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { if (!rollback.isStaged()) { // All calls to restoreUserData should have // completed by now for a non-staged install. rollback.restoreUserDataInProgress = false; rollback.setRestoreUserDataInProgress(false); } rollback.info.setCommittedSessionId(parentSessionId); Loading @@ -490,8 +490,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { ); synchronized (mLock) { rollback.state = Rollback.ROLLBACK_STATE_COMMITTED; rollback.restoreUserDataInProgress = true; rollback.setCommitted(); rollback.setRestoreUserDataInProgress(true); } parentSession.commit(receiver.getIntentSender()); } catch (IOException e) { Loading Loading @@ -618,9 +618,9 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { synchronized (mLock) { for (Rollback rollback : mRollbacks) { if (rollback.isStaged()) { if (rollback.state == Rollback.ROLLBACK_STATE_ENABLING) { if (rollback.isEnabling()) { enabling.add(rollback); } else if (rollback.restoreUserDataInProgress) { } else if (rollback.isRestoreUserDataInProgress()) { restoreInProgress.add(rollback); } Loading @@ -635,8 +635,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { for (Rollback rollback : enabling) { PackageInstaller installer = mContext.getPackageManager().getPackageInstaller(); PackageInstaller.SessionInfo session = installer.getSessionInfo( rollback.stagedSessionId); PackageInstaller.SessionInfo session = installer.getSessionInfo(rollback.getStagedSessionId()); if (session == null || session.isStagedSessionFailed()) { // TODO: Do we need to remove this from // mRollbacks, or is it okay to leave as Loading @@ -650,13 +650,13 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { for (Rollback rollback : restoreInProgress) { PackageInstaller installer = mContext.getPackageManager().getPackageInstaller(); PackageInstaller.SessionInfo session = installer.getSessionInfo( rollback.stagedSessionId); PackageInstaller.SessionInfo session = installer.getSessionInfo(rollback.getStagedSessionId()); // TODO: What if session is null? if (session != null) { if (session.isStagedSessionApplied() || session.isStagedSessionFailed()) { synchronized (mLock) { rollback.restoreUserDataInProgress = false; rollback.setRestoreUserDataInProgress(false); } saveRollback(rollback); } Loading Loading @@ -694,8 +694,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { while (iter.hasNext()) { Rollback rollback = iter.next(); // TODO: Should we remove rollbacks in the ENABLING state here? if (rollback.state == Rollback.ROLLBACK_STATE_AVAILABLE || rollback.state == Rollback.ROLLBACK_STATE_ENABLING) { if (rollback.isEnabling() || rollback.isAvailable()) { for (PackageRollbackInfo info : rollback.info.getPackages()) { if (info.getPackageName().equals(packageName) && !packageVersionsEqual( Loading Loading @@ -761,15 +760,16 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { Iterator<Rollback> iter = mRollbacks.iterator(); while (iter.hasNext()) { Rollback rollback = iter.next(); if (rollback.state != Rollback.ROLLBACK_STATE_AVAILABLE) { if (!rollback.isAvailable()) { continue; } if (!now.isBefore( rollback.timestamp.plusMillis(mRollbackLifetimeDurationInMillis))) { rollback.getTimestamp() .plusMillis(mRollbackLifetimeDurationInMillis))) { iter.remove(); deleteRollback(rollback); } else if (oldest == null || oldest.isAfter(rollback.timestamp)) { oldest = rollback.timestamp; } else if (oldest == null || oldest.isAfter(rollback.getTimestamp())) { oldest = rollback.getTimestamp(); } } } Loading Loading @@ -877,7 +877,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { synchronized (mLock) { for (int i = 0; i < mRollbacks.size(); ++i) { Rollback rollback = mRollbacks.get(i); if (rollback.apkSessionId == parentSession.getSessionId()) { if (rollback.getApkSessionId() == parentSession.getSessionId()) { // This is the apk session for a staged session with rollback enabled. We do not // need to create a new rollback for this session. return true; Loading Loading @@ -1020,7 +1020,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // staged installs for (int i = 0; i < mRollbacks.size(); i++) { Rollback rollback = mRollbacks.get(i); if (rollback.state != Rollback.ROLLBACK_STATE_ENABLING) { if (!rollback.isEnabling()) { continue; } Loading Loading @@ -1053,7 +1053,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { synchronized (mLock) { for (int i = 0; i < mRollbacks.size(); ++i) { Rollback candidate = mRollbacks.get(i); if (candidate.restoreUserDataInProgress) { if (candidate.isRestoreUserDataInProgress()) { info = getPackageRollbackInfo(candidate, packageName); if (info != null) { rollback = candidate; Loading Loading @@ -1146,8 +1146,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { synchronized (mLock) { for (int i = 0; i < mRollbacks.size(); ++i) { Rollback candidate = mRollbacks.get(i); if (candidate.stagedSessionId == originalSessionId) { candidate.apkSessionId = apkSessionId; if (candidate.getStagedSessionId() == originalSessionId) { candidate.setApkSessionId(apkSessionId); rollback = candidate; break; } Loading Loading @@ -1333,8 +1333,8 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { // to a new package being installed. Won't this revive an expired // rollback? Consider adding a ROLLBACK_STATE_EXPIRED to address this. synchronized (mLock) { rollback.state = Rollback.ROLLBACK_STATE_AVAILABLE; rollback.timestamp = Instant.now(); rollback.setAvailable(); rollback.setTimestamp(Instant.now()); } saveRollback(rollback); Loading Loading @@ -1434,9 +1434,9 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { ipw.println(info.getRollbackId() + ":"); ipw.increaseIndent(); ipw.println("-state: " + rollback.getStateAsString()); ipw.println("-timestamp: " + rollback.timestamp); if (rollback.stagedSessionId != -1) { ipw.println("-stagedSessionId: " + rollback.stagedSessionId); ipw.println("-timestamp: " + rollback.getTimestamp()); if (rollback.getStagedSessionId() != -1) { ipw.println("-stagedSessionId: " + rollback.getStagedSessionId()); } ipw.println("-packages:"); ipw.increaseIndent(); Loading @@ -1446,7 +1446,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { + " -> " + pkg.getVersionRolledBackTo().getLongVersionCode()); } ipw.decreaseIndent(); if (rollback.state == Rollback.ROLLBACK_STATE_COMMITTED) { if (rollback.isCommitted()) { ipw.println("-causePackages:"); ipw.increaseIndent(); for (VersionedPackage cPkg : info.getCausePackages()) { Loading
services/core/java/com/android/server/rollback/RollbackStore.java +10 −11 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package com.android.server.rollback; import static com.android.server.rollback.Rollback.rollbackStateFromString; import static com.android.server.rollback.Rollback.rollbackStateToString; import android.annotation.NonNull; import android.content.pm.VersionedPackage; Loading Loading @@ -216,7 +215,7 @@ class RollbackStore { static void backupPackageCodePath(Rollback rollback, String packageName, String codePath) throws IOException { File sourceFile = new File(codePath); File targetDir = new File(rollback.backupDir, packageName); File targetDir = new File(rollback.getBackupDir(), packageName); targetDir.mkdirs(); File targetFile = new File(targetDir, sourceFile.getName()); Loading @@ -229,7 +228,7 @@ class RollbackStore { * Includes the base apk and any splits. Returns null if none found. */ static File[] getPackageCodePaths(Rollback rollback, String packageName) { File targetDir = new File(rollback.backupDir, packageName); File targetDir = new File(rollback.getBackupDir(), packageName); File[] files = targetDir.listFiles(); if (files == null || files.length == 0) { return null; Loading @@ -243,7 +242,7 @@ class RollbackStore { */ static void deletePackageCodePaths(Rollback rollback) { for (PackageRollbackInfo info : rollback.info.getPackages()) { File targetDir = new File(rollback.backupDir, info.getPackageName()); File targetDir = new File(rollback.getBackupDir(), info.getPackageName()); removeFile(targetDir); } } Loading @@ -255,13 +254,13 @@ class RollbackStore { try { JSONObject dataJson = new JSONObject(); dataJson.put("info", rollbackInfoToJson(rollback.info)); dataJson.put("timestamp", rollback.timestamp.toString()); dataJson.put("stagedSessionId", rollback.stagedSessionId); dataJson.put("state", rollbackStateToString(rollback.state)); dataJson.put("apkSessionId", rollback.apkSessionId); dataJson.put("restoreUserDataInProgress", rollback.restoreUserDataInProgress); dataJson.put("timestamp", rollback.getTimestamp().toString()); dataJson.put("stagedSessionId", rollback.getStagedSessionId()); dataJson.put("state", rollback.getStateAsString()); dataJson.put("apkSessionId", rollback.getApkSessionId()); dataJson.put("restoreUserDataInProgress", rollback.isRestoreUserDataInProgress()); PrintWriter pw = new PrintWriter(new File(rollback.backupDir, "rollback.json")); PrintWriter pw = new PrintWriter(new File(rollback.getBackupDir(), "rollback.json")); pw.println(dataJson.toString()); pw.close(); } catch (JSONException e) { Loading @@ -273,7 +272,7 @@ class RollbackStore { * Removes all persistent storage associated with the given rollback. */ void deleteRollback(Rollback rollback) { removeFile(rollback.backupDir); removeFile(rollback.getBackupDir()); } /** Loading
services/tests/servicestests/src/com/android/server/rollback/RollbackUnitTest.java 0 → 100644 +77 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.rollback; import static com.google.common.truth.Truth.assertThat; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.io.File; @RunWith(JUnit4.class) public class RollbackUnitTest { @Test public void newEmptyStagedRollbackDefaults() { int rollbackId = 123; int sessionId = 567; File file = new File("/test/testing"); Rollback rollback = new Rollback(rollbackId, file, sessionId); assertThat(rollback.isEnabling()).isTrue(); assertThat(rollback.getBackupDir().getAbsolutePath()).isEqualTo("/test/testing"); assertThat(rollback.isStaged()).isTrue(); assertThat(rollback.getStagedSessionId()).isEqualTo(567); } @Test public void newEmptyNonStagedRollbackDefaults() { int rollbackId = 123; File file = new File("/test/testing"); Rollback rollback = new Rollback(rollbackId, file, -1); assertThat(rollback.isEnabling()).isTrue(); assertThat(rollback.getBackupDir().getAbsolutePath()).isEqualTo("/test/testing"); assertThat(rollback.isStaged()).isFalse(); } @Test public void rollbackStateChanges() { Rollback rollback = new Rollback(123, new File("/test/testing"), -1); assertThat(rollback.isEnabling()).isTrue(); assertThat(rollback.isAvailable()).isFalse(); assertThat(rollback.isCommitted()).isFalse(); rollback.setAvailable(); assertThat(rollback.isEnabling()).isFalse(); assertThat(rollback.isAvailable()).isTrue(); assertThat(rollback.isCommitted()).isFalse(); rollback.setCommitted(); assertThat(rollback.isEnabling()).isFalse(); assertThat(rollback.isAvailable()).isFalse(); assertThat(rollback.isCommitted()).isTrue(); } }