Record supported extension versions at rollback creation.

This adds a property to the Rollback class to record which extension
versions were supported at the time of creation.

This will be used to block commit of a rollback if it may result in
an installed app's minExtensionVersion being violated. See
go/sdk-extensions-and-rollback for details.

Bug: 152737927
Test: atest RollbackStoreTest
Test: atest RollbackTest
Merged-In: If770a615a1b23505477d786d6ab204e32d9af4c5
Change-Id: If770a615a1b23505477d786d6ab204e32d9af4c5
This commit is contained in:
Oli Lan
2020-04-17 17:58:33 +01:00
parent db87672d1b
commit 2986572ae8
6 changed files with 189 additions and 18 deletions

View File

@@ -38,6 +38,9 @@ public class SdkExtensions {
private static final int R_EXTENSION_INT; private static final int R_EXTENSION_INT;
static { static {
// Note: when adding more extension versions, the logic that records current
// extension versions when saving a rollback must also be updated.
// At the time of writing this is in RollbackManagerServiceImpl#getExtensionVersions()
R_EXTENSION_INT = SystemProperties.getInt("build.version.extensions.r", 0); R_EXTENSION_INT = SystemProperties.getInt("build.version.extensions.r", 0);
} }

View File

@@ -39,6 +39,7 @@ import android.os.UserManager;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.IntArray; import android.util.IntArray;
import android.util.Slog; import android.util.Slog;
import android.util.SparseIntArray;
import android.util.SparseLongArray; import android.util.SparseLongArray;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
@@ -173,6 +174,12 @@ class Rollback {
@GuardedBy("mLock") @GuardedBy("mLock")
private int mNumPackageSessionsWithSuccess; private int mNumPackageSessionsWithSuccess;
/**
* The extension versions supported at the time of rollback creation. May be null if not set
* at creation time.
*/
@Nullable private final SparseIntArray mExtensionVersions;
/** /**
* Constructs a new, empty Rollback instance. * Constructs a new, empty Rollback instance.
* *
@@ -182,9 +189,11 @@ class Rollback {
* @param userId the user that performed the install with rollback enabled. * @param userId the user that performed the install with rollback enabled.
* @param installerPackageName the installer package name from the original install session. * @param installerPackageName the installer package name from the original install session.
* @param packageSessionIds the session ids for all packages in the install. * @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 stagedSessionId, int userId,
String installerPackageName, int[] packageSessionIds) { String installerPackageName, int[] packageSessionIds,
SparseIntArray extensionVersions) {
this.info = new RollbackInfo(rollbackId, this.info = new RollbackInfo(rollbackId,
/* packages */ new ArrayList<>(), /* packages */ new ArrayList<>(),
/* isStaged */ stagedSessionId != -1, /* isStaged */ stagedSessionId != -1,
@@ -197,11 +206,12 @@ class Rollback {
mState = ROLLBACK_STATE_ENABLING; mState = ROLLBACK_STATE_ENABLING;
mTimestamp = Instant.now(); mTimestamp = Instant.now();
mPackageSessionIds = packageSessionIds != null ? packageSessionIds : new int[0]; mPackageSessionIds = packageSessionIds != null ? packageSessionIds : new int[0];
mExtensionVersions = extensionVersions;
} }
Rollback(int rollbackId, File backupDir, int stagedSessionId, int userId, Rollback(int rollbackId, File backupDir, int stagedSessionId, int userId,
String installerPackageName) { String installerPackageName) {
this(rollbackId, backupDir, stagedSessionId, userId, installerPackageName, null); this(rollbackId, backupDir, stagedSessionId, userId, installerPackageName, null, null);
} }
/** /**
@@ -209,7 +219,7 @@ class Rollback {
*/ */
Rollback(RollbackInfo info, File backupDir, Instant timestamp, int stagedSessionId, Rollback(RollbackInfo info, File backupDir, Instant timestamp, int stagedSessionId,
@RollbackState int state, int apkSessionId, boolean restoreUserDataInProgress, @RollbackState int state, int apkSessionId, boolean restoreUserDataInProgress,
int userId, String installerPackageName) { int userId, String installerPackageName, SparseIntArray extensionVersions) {
this.info = info; this.info = info;
mUserId = userId; mUserId = userId;
mInstallerPackageName = installerPackageName; mInstallerPackageName = installerPackageName;
@@ -219,6 +229,7 @@ class Rollback {
mState = state; mState = state;
mApkSessionId = apkSessionId; mApkSessionId = apkSessionId;
mRestoreUserDataInProgress = restoreUserDataInProgress; mRestoreUserDataInProgress = restoreUserDataInProgress;
mExtensionVersions = extensionVersions;
// TODO(b/120200473): Include this field during persistence. This field will be used to // TODO(b/120200473): Include this field during persistence. This field will be used to
// decide which rollback to expire when ACTION_PACKAGE_REPLACED is received. Note persisting // decide which rollback to expire when ACTION_PACKAGE_REPLACED is received. Note persisting
// this field is not backward compatible. We won't fix b/120200473 until S to minimize the // this field is not backward compatible. We won't fix b/120200473 until S to minimize the
@@ -282,6 +293,14 @@ class Rollback {
return mInstallerPackageName; return mInstallerPackageName;
} }
/**
* Returns the extension versions that were supported at the time that the rollback was created,
* as a mapping from SdkVersion to ExtensionVersion.
*/
@Nullable SparseIntArray getExtensionVersions() {
return mExtensionVersions;
}
/** /**
* Returns true if the rollback is in the ENABLING state. * Returns true if the rollback is in the ENABLING state.
*/ */

View File

@@ -41,6 +41,7 @@ import android.content.rollback.IRollbackManager;
import android.content.rollback.RollbackInfo; import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager; import android.content.rollback.RollbackManager;
import android.os.Binder; import android.os.Binder;
import android.os.Build;
import android.os.Environment; import android.os.Environment;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerExecutor; import android.os.HandlerExecutor;
@@ -49,12 +50,14 @@ import android.os.Process;
import android.os.SystemClock; import android.os.SystemClock;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager; import android.os.UserManager;
import android.os.ext.SdkExtensions;
import android.provider.DeviceConfig; import android.provider.DeviceConfig;
import android.util.IntArray; import android.util.IntArray;
import android.util.Log; import android.util.Log;
import android.util.LongArrayQueue; import android.util.LongArrayQueue;
import android.util.Slog; import android.util.Slog;
import android.util.SparseBooleanArray; import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.DumpUtils; import com.android.internal.util.DumpUtils;
@@ -1274,16 +1277,29 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub {
if (parentSession.isStaged()) { if (parentSession.isStaged()) {
rollback = mRollbackStore.createStagedRollback(rollbackId, parentSessionId, userId, rollback = mRollbackStore.createStagedRollback(rollbackId, parentSessionId, userId,
installerPackageName, packageSessionIds); installerPackageName, packageSessionIds, getExtensionVersions());
} else { } else {
rollback = mRollbackStore.createNonStagedRollback(rollbackId, userId, rollback = mRollbackStore.createNonStagedRollback(rollbackId, userId,
installerPackageName, packageSessionIds); installerPackageName, packageSessionIds, getExtensionVersions());
} }
mRollbacks.add(rollback); mRollbacks.add(rollback);
return rollback; return rollback;
} }
private SparseIntArray getExtensionVersions() {
// This list must be updated whenever the current API level is increased, or should be
// replaced when we have another way of determining the relevant SDK versions.
final int[] relevantSdkVersions = { Build.VERSION_CODES.R };
SparseIntArray result = new SparseIntArray(relevantSdkVersions.length);
for (int i = 0; i < relevantSdkVersions.length; i++) {
result.put(relevantSdkVersions[i],
SdkExtensions.getExtensionVersion(relevantSdkVersions[i]));
}
return result;
}
/** /**
* Returns the Rollback associated with the given session if parent or child session id matches. * Returns the Rollback associated with the given session if parent or child session id matches.
* Returns null if not found. * Returns null if not found.

View File

@@ -21,6 +21,7 @@ import static android.os.UserHandle.USER_SYSTEM;
import static com.android.server.rollback.Rollback.rollbackStateFromString; import static com.android.server.rollback.Rollback.rollbackStateFromString;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.VersionedPackage; import android.content.pm.VersionedPackage;
import android.content.rollback.PackageRollbackInfo; import android.content.rollback.PackageRollbackInfo;
@@ -28,6 +29,7 @@ import android.content.rollback.PackageRollbackInfo.RestoreInfo;
import android.content.rollback.RollbackInfo; import android.content.rollback.RollbackInfo;
import android.util.IntArray; import android.util.IntArray;
import android.util.Slog; import android.util.Slog;
import android.util.SparseIntArray;
import android.util.SparseLongArray; import android.util.SparseLongArray;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
@@ -176,6 +178,35 @@ class RollbackStore {
return ceSnapshotInodes; return ceSnapshotInodes;
} }
private static @Nullable JSONArray extensionVersionsToJson(
@Nullable SparseIntArray extensionVersions) throws JSONException {
if (extensionVersions == null) {
return null;
}
JSONArray array = new JSONArray();
for (int i = 0; i < extensionVersions.size(); i++) {
JSONObject entryJson = new JSONObject();
entryJson.put("sdkVersion", extensionVersions.keyAt(i));
entryJson.put("extensionVersion", extensionVersions.valueAt(i));
array.put(entryJson);
}
return array;
}
private static @Nullable SparseIntArray extensionVersionsFromJson(@Nullable JSONArray json)
throws JSONException {
if (json == null) {
return null;
}
SparseIntArray extensionVersions = new SparseIntArray(json.length());
for (int i = 0; i < json.length(); i++) {
JSONObject entry = json.getJSONObject(i);
extensionVersions.append(
entry.getInt("sdkVersion"), entry.getInt("extensionVersion"));
}
return extensionVersions;
}
private static JSONObject rollbackInfoToJson(RollbackInfo rollback) throws JSONException { private static JSONObject rollbackInfoToJson(RollbackInfo rollback) throws JSONException {
JSONObject json = new JSONObject(); JSONObject json = new JSONObject();
json.put("rollbackId", rollback.getRollbackId()); json.put("rollbackId", rollback.getRollbackId());
@@ -200,10 +231,10 @@ class RollbackStore {
* backupDir assigned. * backupDir assigned.
*/ */
Rollback createNonStagedRollback(int rollbackId, int userId, String installerPackageName, Rollback createNonStagedRollback(int rollbackId, int userId, String installerPackageName,
int[] packageSessionIds) { int[] packageSessionIds, SparseIntArray extensionVersions) {
File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId)); File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId));
return new Rollback(rollbackId, backupDir, -1, userId, installerPackageName, return new Rollback(rollbackId, backupDir, -1, userId, installerPackageName,
packageSessionIds); packageSessionIds, extensionVersions);
} }
/** /**
@@ -211,10 +242,11 @@ class RollbackStore {
* backupDir assigned. * backupDir assigned.
*/ */
Rollback createStagedRollback(int rollbackId, int stagedSessionId, int userId, Rollback createStagedRollback(int rollbackId, int stagedSessionId, int userId,
String installerPackageName, int[] packageSessionIds) { String installerPackageName, int[] packageSessionIds,
SparseIntArray extensionVersions) {
File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId)); File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId));
return new Rollback(rollbackId, backupDir, stagedSessionId, userId, installerPackageName, return new Rollback(rollbackId, backupDir, stagedSessionId, userId, installerPackageName,
packageSessionIds); packageSessionIds, extensionVersions);
} }
/** /**
@@ -272,6 +304,8 @@ class RollbackStore {
dataJson.put("restoreUserDataInProgress", rollback.isRestoreUserDataInProgress()); dataJson.put("restoreUserDataInProgress", rollback.isRestoreUserDataInProgress());
dataJson.put("userId", rollback.getUserId()); dataJson.put("userId", rollback.getUserId());
dataJson.putOpt("installerPackageName", rollback.getInstallerPackageName()); dataJson.putOpt("installerPackageName", rollback.getInstallerPackageName());
dataJson.putOpt(
"extensionVersions", extensionVersionsToJson(rollback.getExtensionVersions()));
PrintWriter pw = new PrintWriter(new File(rollback.getBackupDir(), "rollback.json")); PrintWriter pw = new PrintWriter(new File(rollback.getBackupDir(), "rollback.json"));
pw.println(dataJson.toString()); pw.println(dataJson.toString());
@@ -316,7 +350,8 @@ class RollbackStore {
dataJson.getInt("apkSessionId"), dataJson.getInt("apkSessionId"),
dataJson.getBoolean("restoreUserDataInProgress"), dataJson.getBoolean("restoreUserDataInProgress"),
dataJson.optInt("userId", USER_SYSTEM), dataJson.optInt("userId", USER_SYSTEM),
dataJson.optString("installerPackageName", "")); dataJson.optString("installerPackageName", ""),
extensionVersionsFromJson(dataJson.optJSONArray("extensionVersions")));
} }
private static JSONObject toJson(VersionedPackage pkg) throws JSONException { private static JSONObject toJson(VersionedPackage pkg) throws JSONException {

View File

@@ -21,6 +21,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.content.pm.VersionedPackage; import android.content.pm.VersionedPackage;
import android.content.rollback.PackageRollbackInfo; import android.content.rollback.PackageRollbackInfo;
import android.util.IntArray; import android.util.IntArray;
import android.util.SparseIntArray;
import android.util.SparseLongArray; import android.util.SparseLongArray;
import com.google.common.truth.Correspondence; import com.google.common.truth.Correspondence;
@@ -83,7 +84,7 @@ public class RollbackStoreTest {
} }
}; };
private static final String JSON_ROLLBACK = "{'info':{'rollbackId':123,'packages':" private static final String JSON_ROLLBACK_NO_EXT = "{'info':{'rollbackId':123,'packages':"
+ "[{'versionRolledBackFrom':{'packageName':'blah','longVersionCode':55}," + "[{'versionRolledBackFrom':{'packageName':'blah','longVersionCode':55},"
+ "'versionRolledBackTo':{'packageName':'blah1','longVersionCode':50},'pendingBackups':" + "'versionRolledBackTo':{'packageName':'blah1','longVersionCode':50},'pendingBackups':"
+ "[59,1245,124544],'pendingRestores':[{'userId':498,'appId':32322,'seInfo':'wombles'}," + "[59,1245,124544],'pendingRestores':[{'userId':498,'appId':32322,'seInfo':'wombles'},"
@@ -103,6 +104,28 @@ public class RollbackStoreTest {
+ "'restoreUserDataInProgress':true, 'userId':0," + "'restoreUserDataInProgress':true, 'userId':0,"
+ "'installerPackageName':'some.installer'}"; + "'installerPackageName':'some.installer'}";
private static final String JSON_ROLLBACK = "{'info':{'rollbackId':123,'packages':"
+ "[{'versionRolledBackFrom':{'packageName':'blah','longVersionCode':55},"
+ "'versionRolledBackTo':{'packageName':'blah1','longVersionCode':50},'pendingBackups':"
+ "[59,1245,124544],'pendingRestores':[{'userId':498,'appId':32322,'seInfo':'wombles'},"
+ "{'userId':-895,'appId':1,'seInfo':'pingu'}],'isApex':false,'isApkInApex':false,"
+ "'installedUsers':"
+ "[498468432,1111,98464],'ceSnapshotInodes':[{'userId':1,'ceSnapshotInode':-6},"
+ "{'userId':2222,'ceSnapshotInode':81641654445},{'userId':546546,"
+ "'ceSnapshotInode':345689375}]},{'versionRolledBackFrom':{'packageName':'chips',"
+ "'longVersionCode':28},'versionRolledBackTo':{'packageName':'com.chips.test',"
+ "'longVersionCode':48},'pendingBackups':[5],'pendingRestores':[{'userId':18,"
+ "'appId':-12,'seInfo':''}],'isApex':false,'isApkInApex':false,"
+ "'installedUsers':[55,79],"
+ "'ceSnapshotInodes':[]}],'isStaged':false,'causePackages':[{'packageName':'hello',"
+ "'longVersionCode':23},{'packageName':'something','longVersionCode':999}],"
+ "'committedSessionId':45654465},'timestamp':'2019-10-01T12:29:08.855Z',"
+ "'stagedSessionId':-1,'state':'enabling','apkSessionId':-1,"
+ "'restoreUserDataInProgress':true, 'userId':0,"
+ "'installerPackageName':'some.installer',"
+ "'extensionVersions':[{'sdkVersion':5,'extensionVersion':25},"
+ "{'sdkVersion':30,'extensionVersion':71}]}";
@Rule @Rule
public TemporaryFolder mFolder = new TemporaryFolder(); public TemporaryFolder mFolder = new TemporaryFolder();
@@ -119,7 +142,10 @@ public class RollbackStoreTest {
@Test @Test
public void createNonStaged() { public void createNonStaged() {
Rollback rollback = mRollbackStore.createNonStagedRollback(ID, USER, INSTALLER, null); SparseIntArray extensionVersions = new SparseIntArray();
extensionVersions.put(30, 71);
Rollback rollback = mRollbackStore.createNonStagedRollback(
ID, USER, INSTALLER, null, extensionVersions);
assertThat(rollback.getBackupDir().getAbsolutePath()) assertThat(rollback.getBackupDir().getAbsolutePath())
.isEqualTo(mFolder.getRoot().getAbsolutePath() + "/" + ID); .isEqualTo(mFolder.getRoot().getAbsolutePath() + "/" + ID);
@@ -128,11 +154,16 @@ public class RollbackStoreTest {
assertThat(rollback.info.getRollbackId()).isEqualTo(ID); assertThat(rollback.info.getRollbackId()).isEqualTo(ID);
assertThat(rollback.info.getPackages()).isEmpty(); assertThat(rollback.info.getPackages()).isEmpty();
assertThat(rollback.isEnabling()).isTrue(); assertThat(rollback.isEnabling()).isTrue();
assertThat(rollback.getExtensionVersions().toString())
.isEqualTo(extensionVersions.toString());
} }
@Test @Test
public void createStaged() { public void createStaged() {
Rollback rollback = mRollbackStore.createStagedRollback(ID, 897, USER, INSTALLER, null); SparseIntArray extensionVersions = new SparseIntArray();
extensionVersions.put(30, 71);
Rollback rollback = mRollbackStore.createStagedRollback(
ID, 897, USER, INSTALLER, null, extensionVersions);
assertThat(rollback.getBackupDir().getAbsolutePath()) assertThat(rollback.getBackupDir().getAbsolutePath())
.isEqualTo(mFolder.getRoot().getAbsolutePath() + "/" + ID); .isEqualTo(mFolder.getRoot().getAbsolutePath() + "/" + ID);
@@ -143,11 +174,17 @@ public class RollbackStoreTest {
assertThat(rollback.info.getRollbackId()).isEqualTo(ID); assertThat(rollback.info.getRollbackId()).isEqualTo(ID);
assertThat(rollback.info.getPackages()).isEmpty(); assertThat(rollback.info.getPackages()).isEmpty();
assertThat(rollback.isEnabling()).isTrue(); assertThat(rollback.isEnabling()).isTrue();
assertThat(rollback.getExtensionVersions().toString())
.isEqualTo(extensionVersions.toString());
} }
@Test @Test
public void saveAndLoadRollback() { public void saveAndLoadRollback() {
Rollback origRb = mRollbackStore.createNonStagedRollback(ID, USER, INSTALLER, null); SparseIntArray extensionVersions = new SparseIntArray();
extensionVersions.put(5, 25);
extensionVersions.put(30, 71);
Rollback origRb = mRollbackStore.createNonStagedRollback(
ID, USER, INSTALLER, null, extensionVersions);
origRb.setRestoreUserDataInProgress(true); origRb.setRestoreUserDataInProgress(true);
origRb.info.getCausePackages().add(new VersionedPackage("com.made.up", 2)); origRb.info.getCausePackages().add(new VersionedPackage("com.made.up", 2));
@@ -195,9 +232,63 @@ public class RollbackStoreTest {
assertRollbacksAreEquivalent(loadedRb, origRb); assertRollbacksAreEquivalent(loadedRb, origRb);
} }
@Test
public void loadFromJsonNoExtensionVersions() throws Exception {
Rollback expectedRb =
mRollbackStore.createNonStagedRollback(ID, USER, INSTALLER, null, null);
expectedRb.setTimestamp(Instant.parse("2019-10-01T12:29:08.855Z"));
expectedRb.setRestoreUserDataInProgress(true);
expectedRb.info.getCausePackages().add(new VersionedPackage("hello", 23));
expectedRb.info.getCausePackages().add(new VersionedPackage("something", 999));
expectedRb.info.setCommittedSessionId(45654465);
PackageRollbackInfo pkgInfo1 = new PackageRollbackInfo(new VersionedPackage("blah", 55),
new VersionedPackage("blah1", 50), new IntArray(), new ArrayList<>(),
false, false, new IntArray(), new SparseLongArray());
pkgInfo1.getPendingBackups().add(59);
pkgInfo1.getPendingBackups().add(1245);
pkgInfo1.getPendingBackups().add(124544);
pkgInfo1.getCeSnapshotInodes().put(546546, 345689375);
pkgInfo1.getCeSnapshotInodes().put(2222, 81641654445L);
pkgInfo1.getCeSnapshotInodes().put(1, -6);
pkgInfo1.getPendingRestores().add(
new PackageRollbackInfo.RestoreInfo(498, 32322, "wombles"));
pkgInfo1.getPendingRestores().add(
new PackageRollbackInfo.RestoreInfo(-895, 1, "pingu"));
pkgInfo1.getSnapshottedUsers().add(498468432);
pkgInfo1.getSnapshottedUsers().add(1111);
pkgInfo1.getSnapshottedUsers().add(98464);
PackageRollbackInfo pkgInfo2 = new PackageRollbackInfo(new VersionedPackage("chips", 28),
new VersionedPackage("com.chips.test", 48), new IntArray(), new ArrayList<>(),
false, false, new IntArray(), new SparseLongArray());
pkgInfo2.getPendingBackups().add(5);
pkgInfo2.getPendingRestores().add(
new PackageRollbackInfo.RestoreInfo(18, -12, ""));
pkgInfo2.getSnapshottedUsers().add(55);
pkgInfo2.getSnapshottedUsers().add(79);
expectedRb.info.getPackages().add(pkgInfo1);
expectedRb.info.getPackages().add(pkgInfo2);
Rollback parsedRb = RollbackStore.rollbackFromJson(
new JSONObject(JSON_ROLLBACK_NO_EXT), expectedRb.getBackupDir());
assertRollbacksAreEquivalent(parsedRb, expectedRb);
}
@Test @Test
public void loadFromJson() throws Exception { public void loadFromJson() throws Exception {
Rollback expectedRb = mRollbackStore.createNonStagedRollback(ID, USER, INSTALLER, null); SparseIntArray extensionVersions = new SparseIntArray();
extensionVersions.put(5, 25);
extensionVersions.put(30, 71);
Rollback expectedRb = mRollbackStore.createNonStagedRollback(
ID, USER, INSTALLER, null, extensionVersions);
expectedRb.setTimestamp(Instant.parse("2019-10-01T12:29:08.855Z")); expectedRb.setTimestamp(Instant.parse("2019-10-01T12:29:08.855Z"));
expectedRb.setRestoreUserDataInProgress(true); expectedRb.setRestoreUserDataInProgress(true);
@@ -246,7 +337,7 @@ public class RollbackStoreTest {
@Test @Test
public void saveAndDelete() { public void saveAndDelete() {
Rollback rollback = mRollbackStore.createNonStagedRollback(ID, USER, INSTALLER, null); Rollback rollback = mRollbackStore.createNonStagedRollback(ID, USER, INSTALLER, null, null);
RollbackStore.saveRollback(rollback); RollbackStore.saveRollback(rollback);
@@ -294,6 +385,13 @@ public class RollbackStoreTest {
assertThat(a.getUserId()).isEqualTo(b.getUserId()); assertThat(a.getUserId()).isEqualTo(b.getUserId());
assertThat(a.getInstallerPackageName()).isEqualTo(b.getInstallerPackageName()); assertThat(a.getInstallerPackageName()).isEqualTo(b.getInstallerPackageName());
if (a.getExtensionVersions() == null) {
assertThat(b.getExtensionVersions()).isNull();
} else {
assertThat(b.getExtensionVersions().toString())
.isEqualTo(a.getExtensionVersions().toString());
}
} }
private void assertPackageRollbacksAreEquivalent(PackageRollbackInfo b, PackageRollbackInfo a) { private void assertPackageRollbacksAreEquivalent(PackageRollbackInfo b, PackageRollbackInfo a) {

View File

@@ -317,7 +317,7 @@ public class RollbackUnitTest {
public void notifySessionWithSuccess() { public void notifySessionWithSuccess() {
int[] sessionIds = new int[]{ 7777, 8888 }; int[] sessionIds = new int[]{ 7777, 8888 };
Rollback rollback = new Rollback(123, new File("/test/testing"), -1, USER, INSTALLER, Rollback rollback = new Rollback(123, new File("/test/testing"), -1, USER, INSTALLER,
sessionIds); sessionIds, null);
// The 1st invocation returns false because not all child sessions are notified. // The 1st invocation returns false because not all child sessions are notified.
assertThat(rollback.notifySessionWithSuccess()).isFalse(); assertThat(rollback.notifySessionWithSuccess()).isFalse();
// The 2nd invocation returns true because now all child sessions are notified. // The 2nd invocation returns true because now all child sessions are notified.
@@ -328,7 +328,7 @@ public class RollbackUnitTest {
public void allPackagesEnabled() { public void allPackagesEnabled() {
int[] sessionIds = new int[]{ 7777, 8888 }; int[] sessionIds = new int[]{ 7777, 8888 };
Rollback rollback = new Rollback(123, new File("/test/testing"), -1, USER, INSTALLER, Rollback rollback = new Rollback(123, new File("/test/testing"), -1, USER, INSTALLER,
sessionIds); sessionIds, null);
// #allPackagesEnabled returns false when 1 out of 2 packages is enabled. // #allPackagesEnabled returns false when 1 out of 2 packages is enabled.
rollback.info.getPackages().add(newPkgInfoFor(PKG_1, 12, 10, false)); rollback.info.getPackages().add(newPkgInfoFor(PKG_1, 12, 10, false));
assertThat(rollback.allPackagesEnabled()).isFalse(); assertThat(rollback.allPackagesEnabled()).isFalse();