diff options
| -rw-r--r-- | services/core/java/com/android/server/rollback/RollbackStore.java | 23 | ||||
| -rw-r--r-- | services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java | 318 |
2 files changed, 333 insertions, 8 deletions
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java index a9331aa5648f..5b226245a892 100644 --- a/services/core/java/com/android/server/rollback/RollbackStore.java +++ b/services/core/java/com/android/server/rollback/RollbackStore.java @@ -28,6 +28,7 @@ import android.util.Slog; import android.util.SparseLongArray; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import libcore.io.IoUtils; @@ -288,19 +289,25 @@ class RollbackStore { JSONObject dataJson = new JSONObject( IoUtils.readFileAsString(rollbackJsonFile.getAbsolutePath())); - return new Rollback( - rollbackInfoFromJson(dataJson.getJSONObject("info")), - backupDir, - Instant.parse(dataJson.getString("timestamp")), - dataJson.getInt("stagedSessionId"), - rollbackStateFromString(dataJson.getString("state")), - dataJson.getInt("apkSessionId"), - dataJson.getBoolean("restoreUserDataInProgress")); + return rollbackFromJson(dataJson, backupDir); } catch (JSONException | DateTimeParseException | ParseException e) { throw new IOException(e); } } + @VisibleForTesting + static Rollback rollbackFromJson(JSONObject dataJson, File backupDir) + throws JSONException, ParseException { + return new Rollback( + rollbackInfoFromJson(dataJson.getJSONObject("info")), + backupDir, + Instant.parse(dataJson.getString("timestamp")), + dataJson.getInt("stagedSessionId"), + rollbackStateFromString(dataJson.getString("state")), + dataJson.getInt("apkSessionId"), + dataJson.getBoolean("restoreUserDataInProgress")); + } + private static JSONObject toJson(VersionedPackage pkg) throws JSONException { JSONObject json = new JSONObject(); json.put("packageName", pkg.getPackageName()); diff --git a/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java new file mode 100644 index 000000000000..ee3b15a97f26 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java @@ -0,0 +1,318 @@ +/* + * 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 android.content.pm.VersionedPackage; +import android.content.rollback.PackageRollbackInfo; +import android.util.IntArray; +import android.util.SparseLongArray; + +import com.google.common.truth.Correspondence; + +import org.json.JSONObject; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.io.File; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +@RunWith(JUnit4.class) +public class RollbackStoreTest { + + private static final int ID = 123; + + private static final Correspondence<VersionedPackage, VersionedPackage> VER_PKG_CORR = + new Correspondence<VersionedPackage, VersionedPackage>() { + @Override + public boolean compare(VersionedPackage a, VersionedPackage b) { + if (a == null || b == null) { + return a == b; + } + return a.getLongVersionCode() == b.getLongVersionCode() + && Objects.equals(a.getPackageName(), b.getPackageName()); + } + + @Override + public String toString() { + return "is the same as"; + } + }; + + private static final Correspondence<PackageRollbackInfo.RestoreInfo, + PackageRollbackInfo.RestoreInfo> + RESTORE_INFO_CORR = + new Correspondence<PackageRollbackInfo.RestoreInfo, PackageRollbackInfo.RestoreInfo>() { + @Override + public boolean compare(PackageRollbackInfo.RestoreInfo a, + PackageRollbackInfo.RestoreInfo b) { + if (a == null || b == null) { + return a == b; + } + return a.userId == b.userId + && a.appId == b.appId + && Objects.equals(a.seInfo, b.seInfo); + } + + @Override + public String toString() { + return "is the same as"; + } + }; + + 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,'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,'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}"; + + @Rule + public TemporaryFolder mFolder = new TemporaryFolder(); + + private File mRollbackDir; + + private RollbackStore mRollbackStore; + + @Before + public void setUp() throws Exception { + mRollbackStore = new RollbackStore(mFolder.getRoot()); + mRollbackDir = mFolder.newFolder(ID + ""); + mFolder.newFile("rollback.json"); + } + + @Test + public void createNonStaged() { + Rollback rollback = mRollbackStore.createNonStagedRollback(ID); + + assertThat(rollback.getBackupDir().getAbsolutePath()) + .isEqualTo(mFolder.getRoot().getAbsolutePath() + "/" + ID); + + assertThat(rollback.isStaged()).isFalse(); + assertThat(rollback.info.getRollbackId()).isEqualTo(ID); + assertThat(rollback.info.getPackages()).isEmpty(); + assertThat(rollback.isEnabling()).isTrue(); + } + + @Test + public void createStaged() { + Rollback rollback = mRollbackStore.createStagedRollback(ID, 897); + + assertThat(rollback.getBackupDir().getAbsolutePath()) + .isEqualTo(mFolder.getRoot().getAbsolutePath() + "/" + ID); + + assertThat(rollback.isStaged()).isTrue(); + assertThat(rollback.getStagedSessionId()).isEqualTo(897); + + assertThat(rollback.info.getRollbackId()).isEqualTo(ID); + assertThat(rollback.info.getPackages()).isEmpty(); + assertThat(rollback.isEnabling()).isTrue(); + } + + @Test + public void saveAndLoadRollback() { + Rollback origRb = mRollbackStore.createNonStagedRollback(ID); + + origRb.setRestoreUserDataInProgress(true); + origRb.info.getCausePackages().add(new VersionedPackage("com.made.up", 2)); + origRb.info.getCausePackages().add(new VersionedPackage("com.pack.age", 99)); + origRb.info.setCommittedSessionId(123456); + + PackageRollbackInfo pkgInfo1 = + new PackageRollbackInfo(new VersionedPackage("com.made.up", 18), + new VersionedPackage("com.something.else", 5), new IntArray(), + new ArrayList<>(), false, new IntArray(), new SparseLongArray()); + pkgInfo1.getPendingBackups().add(8); + pkgInfo1.getPendingBackups().add(888); + pkgInfo1.getPendingBackups().add(88885); + pkgInfo1.getCeSnapshotInodes().put(12, 424); + pkgInfo1.getCeSnapshotInodes().put(222772, 10000000000L); + pkgInfo1.getCeSnapshotInodes().put(10, -67); + + pkgInfo1.getPendingRestores().add( + new PackageRollbackInfo.RestoreInfo(4980, 3442322, "seInfo")); + pkgInfo1.getPendingRestores().add( + new PackageRollbackInfo.RestoreInfo(-89, 15, "otherSeInfo")); + + pkgInfo1.getSnapshottedUsers().add(11); + pkgInfo1.getSnapshottedUsers().add(1); + pkgInfo1.getSnapshottedUsers().add(0); + + PackageRollbackInfo pkgInfo2 = new PackageRollbackInfo( + new VersionedPackage("another.package", 2), + new VersionedPackage("com.test.ing", 48888), new IntArray(), new ArrayList<>(), + false, new IntArray(), new SparseLongArray()); + pkgInfo2.getPendingBackups().add(57); + + pkgInfo2.getPendingRestores().add( + new PackageRollbackInfo.RestoreInfo(180, -120, "")); + + origRb.info.getPackages().add(pkgInfo1); + origRb.info.getPackages().add(pkgInfo2); + + RollbackStore.saveRollback(origRb); + + List<Rollback> loadedRollbacks = mRollbackStore.loadRollbacks(); + assertThat(loadedRollbacks).hasSize(1); + Rollback loadedRb = loadedRollbacks.get(0); + + assertRollbacksAreEquivalent(loadedRb, origRb); + } + + @Test + public void loadFromJson() throws Exception { + Rollback expectedRb = mRollbackStore.createNonStagedRollback(ID); + + 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, 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, 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), expectedRb.getBackupDir()); + + assertRollbacksAreEquivalent(parsedRb, expectedRb); + } + + @Test + public void saveAndDelete() { + Rollback rollback = mRollbackStore.createNonStagedRollback(ID); + + RollbackStore.saveRollback(rollback); + + File expectedFile = new File(mRollbackDir.getAbsolutePath() + "/rollback.json"); + + assertThat(expectedFile.exists()).isTrue(); + + RollbackStore.deleteRollback(rollback); + + assertThat(expectedFile.exists()).isFalse(); + } + + private void assertRollbacksAreEquivalent(Rollback b, Rollback a) { + assertThat(b.info.getRollbackId()).isEqualTo(ID); + + assertThat(b.getBackupDir()).isEqualTo(a.getBackupDir()); + + assertThat(b.isRestoreUserDataInProgress()) + .isEqualTo(a.isRestoreUserDataInProgress()); + + assertThat(b.getTimestamp()).isEqualTo(a.getTimestamp()); + + assertThat(b.isEnabling()).isEqualTo(a.isEnabling()); + assertThat(b.isAvailable()).isEqualTo(a.isAvailable()); + assertThat(b.isCommitted()).isEqualTo(a.isCommitted()); + + assertThat(b.isStaged()).isEqualTo(a.isStaged()); + + assertThat(b.getApexPackageNames()) + .containsExactlyElementsIn(a.getApexPackageNames()); + + assertThat(b.getStagedSessionId()).isEqualTo(a.getStagedSessionId()); + + assertThat(b.info.getCommittedSessionId()).isEqualTo(a.info.getCommittedSessionId()); + + assertThat(b.info.getCausePackages()).comparingElementsUsing(VER_PKG_CORR) + .containsExactlyElementsIn(a.info.getCausePackages()); + + assertThat(b.info.getPackages()).hasSize(a.info.getPackages().size()); + + for (int i = 0; i < b.info.getPackages().size(); i++) { + assertPackageRollbacksAreEquivalent( + b.info.getPackages().get(i), a.info.getPackages().get(i)); + } + } + + private void assertPackageRollbacksAreEquivalent(PackageRollbackInfo b, PackageRollbackInfo a) { + assertThat(b.getPackageName()).isEqualTo(a.getPackageName()); + + assertThat(b.getVersionRolledBackFrom().getLongVersionCode()) + .isEqualTo(a.getVersionRolledBackFrom().getLongVersionCode()); + assertThat(b.getVersionRolledBackFrom().getPackageName()) + .isEqualTo(a.getVersionRolledBackFrom().getPackageName()); + + assertThat(b.getVersionRolledBackTo().getLongVersionCode()) + .isEqualTo(a.getVersionRolledBackTo().getLongVersionCode()); + assertThat(b.getVersionRolledBackTo().getPackageName()) + .isEqualTo(a.getVersionRolledBackTo().getPackageName()); + + assertThat(b.getPendingBackups().toArray()).isEqualTo(a.getPendingBackups().toArray()); + + assertThat(b.getPendingRestores()).comparingElementsUsing(RESTORE_INFO_CORR) + .containsExactlyElementsIn(a.getPendingRestores()); + + assertThat(b.isApex()).isEqualTo(a.isApex()); + + assertThat(b.getSnapshottedUsers().toArray()).isEqualTo(a.getSnapshottedUsers().toArray()); + + assertThat(b.getCeSnapshotInodes().toString()) + .isEqualTo(a.getCeSnapshotInodes().toString()); + } + +} |