Loading apex/sdkextensions/framework/java/android/os/ext/SdkExtensions.java +3 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,9 @@ public class SdkExtensions { private static final int R_EXTENSION_INT; 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); } Loading services/core/java/com/android/server/rollback/Rollback.java +22 −3 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.text.TextUtils; import android.util.Slog; import android.util.SparseIntArray; import android.util.SparseLongArray; import com.android.internal.annotations.GuardedBy; Loading Loading @@ -172,6 +173,12 @@ class Rollback { @GuardedBy("mLock") 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. * Loading @@ -181,9 +188,11 @@ class 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, String installerPackageName, int[] packageSessionIds) { String installerPackageName, int[] packageSessionIds, SparseIntArray extensionVersions) { this.info = new RollbackInfo(rollbackId, /* packages */ new ArrayList<>(), /* isStaged */ stagedSessionId != -1, Loading @@ -196,11 +205,12 @@ class Rollback { mState = ROLLBACK_STATE_ENABLING; mTimestamp = Instant.now(); mPackageSessionIds = packageSessionIds != null ? packageSessionIds : new int[0]; mExtensionVersions = extensionVersions; } Rollback(int rollbackId, File backupDir, int stagedSessionId, int userId, String installerPackageName) { this(rollbackId, backupDir, stagedSessionId, userId, installerPackageName, null); this(rollbackId, backupDir, stagedSessionId, userId, installerPackageName, null, null); } /** Loading @@ -208,7 +218,7 @@ class Rollback { */ Rollback(RollbackInfo info, File backupDir, Instant timestamp, int stagedSessionId, @RollbackState int state, int apkSessionId, boolean restoreUserDataInProgress, int userId, String installerPackageName) { int userId, String installerPackageName, SparseIntArray extensionVersions) { this.info = info; mUserId = userId; mInstallerPackageName = installerPackageName; Loading @@ -218,6 +228,7 @@ class Rollback { mState = state; mApkSessionId = apkSessionId; mRestoreUserDataInProgress = restoreUserDataInProgress; mExtensionVersions = extensionVersions; // 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 // this field is not backward compatible. We won't fix b/120200473 until S to minimize the Loading Loading @@ -281,6 +292,14 @@ class Rollback { 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. */ Loading services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +18 −2 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import android.content.rollback.IRollbackManager; import android.content.rollback.RollbackInfo; import android.content.rollback.RollbackManager; import android.os.Binder; import android.os.Build; import android.os.Environment; import android.os.Handler; import android.os.HandlerExecutor; Loading @@ -49,12 +50,14 @@ import android.os.Process; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.os.ext.SdkExtensions; import android.provider.DeviceConfig; import android.util.IntArray; import android.util.Log; import android.util.LongArrayQueue; import android.util.Slog; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.DumpUtils; Loading Loading @@ -1312,16 +1315,29 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { final Rollback rollback; if (parentSession.isStaged()) { rollback = mRollbackStore.createStagedRollback(rollbackId, parentSessionId, userId, installerPackageName, packageSessionIds); installerPackageName, packageSessionIds, getExtensionVersions()); } else { rollback = mRollbackStore.createNonStagedRollback(rollbackId, userId, installerPackageName, packageSessionIds); installerPackageName, packageSessionIds, getExtensionVersions()); } mRollbacks.add(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 null if not found. Loading services/core/java/com/android/server/rollback/RollbackStore.java +40 −5 Original line number Diff line number Diff line Loading @@ -21,12 +21,14 @@ import static android.os.UserHandle.USER_SYSTEM; import static com.android.server.rollback.Rollback.rollbackStateFromString; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.PackageManager; import android.content.pm.VersionedPackage; import android.content.rollback.PackageRollbackInfo; import android.content.rollback.PackageRollbackInfo.RestoreInfo; import android.content.rollback.RollbackInfo; import android.util.Slog; import android.util.SparseIntArray; import android.util.SparseLongArray; import com.android.internal.annotations.GuardedBy; Loading Loading @@ -171,6 +173,35 @@ class RollbackStore { 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 { JSONObject json = new JSONObject(); json.put("rollbackId", rollback.getRollbackId()); Loading @@ -195,10 +226,10 @@ class RollbackStore { * backupDir assigned. */ Rollback createNonStagedRollback(int rollbackId, int userId, String installerPackageName, int[] packageSessionIds) { int[] packageSessionIds, SparseIntArray extensionVersions) { File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId)); return new Rollback(rollbackId, backupDir, -1, userId, installerPackageName, packageSessionIds); packageSessionIds, extensionVersions); } /** Loading @@ -206,10 +237,11 @@ class RollbackStore { * backupDir assigned. */ 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)); return new Rollback(rollbackId, backupDir, stagedSessionId, userId, installerPackageName, packageSessionIds); packageSessionIds, extensionVersions); } /** Loading Loading @@ -267,6 +299,8 @@ class RollbackStore { dataJson.put("restoreUserDataInProgress", rollback.isRestoreUserDataInProgress()); dataJson.put("userId", rollback.getUserId()); dataJson.putOpt("installerPackageName", rollback.getInstallerPackageName()); dataJson.putOpt( "extensionVersions", extensionVersionsToJson(rollback.getExtensionVersions())); PrintWriter pw = new PrintWriter(new File(rollback.getBackupDir(), "rollback.json")); pw.println(dataJson.toString()); Loading Loading @@ -311,7 +345,8 @@ class RollbackStore { dataJson.getInt("apkSessionId"), dataJson.getBoolean("restoreUserDataInProgress"), dataJson.optInt("userId", USER_SYSTEM), dataJson.optString("installerPackageName", "")); dataJson.optString("installerPackageName", ""), extensionVersionsFromJson(dataJson.optJSONArray("extensionVersions"))); } private static JSONObject toJson(VersionedPackage pkg) throws JSONException { Loading services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java +104 −6 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat; import android.content.pm.VersionedPackage; import android.content.rollback.PackageRollbackInfo; import android.util.SparseIntArray; import android.util.SparseLongArray; import com.google.common.truth.Correspondence; Loading Loading @@ -82,7 +83,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}," + "'versionRolledBackTo':{'packageName':'blah1','longVersionCode':50},'pendingBackups':" + "[59,1245,124544],'pendingRestores':[{'userId':498,'appId':32322,'seInfo':'wombles'}," Loading @@ -102,6 +103,28 @@ public class RollbackStoreTest { + "'restoreUserDataInProgress':true, 'userId':0," + "'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 public TemporaryFolder mFolder = new TemporaryFolder(); Loading @@ -118,7 +141,10 @@ public class RollbackStoreTest { @Test 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()) .isEqualTo(mFolder.getRoot().getAbsolutePath() + "/" + ID); Loading @@ -127,11 +153,16 @@ public class RollbackStoreTest { assertThat(rollback.info.getRollbackId()).isEqualTo(ID); assertThat(rollback.info.getPackages()).isEmpty(); assertThat(rollback.isEnabling()).isTrue(); assertThat(rollback.getExtensionVersions().toString()) .isEqualTo(extensionVersions.toString()); } @Test 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()) .isEqualTo(mFolder.getRoot().getAbsolutePath() + "/" + ID); Loading @@ -142,11 +173,17 @@ public class RollbackStoreTest { assertThat(rollback.info.getRollbackId()).isEqualTo(ID); assertThat(rollback.info.getPackages()).isEmpty(); assertThat(rollback.isEnabling()).isTrue(); assertThat(rollback.getExtensionVersions().toString()) .isEqualTo(extensionVersions.toString()); } @Test 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.info.getCausePackages().add(new VersionedPackage("com.made.up", 2)); Loading Loading @@ -194,9 +231,63 @@ public class RollbackStoreTest { 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 ArrayList<>(), new ArrayList<>(), false, false, new ArrayList<>(), 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 ArrayList<>(), new ArrayList<>(), false, false, new ArrayList<>(), 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 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.setRestoreUserDataInProgress(true); Loading Loading @@ -245,7 +336,7 @@ public class RollbackStoreTest { @Test public void saveAndDelete() { Rollback rollback = mRollbackStore.createNonStagedRollback(ID, USER, INSTALLER, null); Rollback rollback = mRollbackStore.createNonStagedRollback(ID, USER, INSTALLER, null, null); RollbackStore.saveRollback(rollback); Loading Loading @@ -293,6 +384,13 @@ public class RollbackStoreTest { assertThat(a.getUserId()).isEqualTo(b.getUserId()); 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) { Loading Loading
apex/sdkextensions/framework/java/android/os/ext/SdkExtensions.java +3 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,9 @@ public class SdkExtensions { private static final int R_EXTENSION_INT; 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); } Loading
services/core/java/com/android/server/rollback/Rollback.java +22 −3 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.text.TextUtils; import android.util.Slog; import android.util.SparseIntArray; import android.util.SparseLongArray; import com.android.internal.annotations.GuardedBy; Loading Loading @@ -172,6 +173,12 @@ class Rollback { @GuardedBy("mLock") 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. * Loading @@ -181,9 +188,11 @@ class 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, String installerPackageName, int[] packageSessionIds) { String installerPackageName, int[] packageSessionIds, SparseIntArray extensionVersions) { this.info = new RollbackInfo(rollbackId, /* packages */ new ArrayList<>(), /* isStaged */ stagedSessionId != -1, Loading @@ -196,11 +205,12 @@ class Rollback { mState = ROLLBACK_STATE_ENABLING; mTimestamp = Instant.now(); mPackageSessionIds = packageSessionIds != null ? packageSessionIds : new int[0]; mExtensionVersions = extensionVersions; } Rollback(int rollbackId, File backupDir, int stagedSessionId, int userId, String installerPackageName) { this(rollbackId, backupDir, stagedSessionId, userId, installerPackageName, null); this(rollbackId, backupDir, stagedSessionId, userId, installerPackageName, null, null); } /** Loading @@ -208,7 +218,7 @@ class Rollback { */ Rollback(RollbackInfo info, File backupDir, Instant timestamp, int stagedSessionId, @RollbackState int state, int apkSessionId, boolean restoreUserDataInProgress, int userId, String installerPackageName) { int userId, String installerPackageName, SparseIntArray extensionVersions) { this.info = info; mUserId = userId; mInstallerPackageName = installerPackageName; Loading @@ -218,6 +228,7 @@ class Rollback { mState = state; mApkSessionId = apkSessionId; mRestoreUserDataInProgress = restoreUserDataInProgress; mExtensionVersions = extensionVersions; // 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 // this field is not backward compatible. We won't fix b/120200473 until S to minimize the Loading Loading @@ -281,6 +292,14 @@ class Rollback { 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. */ Loading
services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +18 −2 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import android.content.rollback.IRollbackManager; import android.content.rollback.RollbackInfo; import android.content.rollback.RollbackManager; import android.os.Binder; import android.os.Build; import android.os.Environment; import android.os.Handler; import android.os.HandlerExecutor; Loading @@ -49,12 +50,14 @@ import android.os.Process; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; import android.os.ext.SdkExtensions; import android.provider.DeviceConfig; import android.util.IntArray; import android.util.Log; import android.util.LongArrayQueue; import android.util.Slog; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.DumpUtils; Loading Loading @@ -1312,16 +1315,29 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { final Rollback rollback; if (parentSession.isStaged()) { rollback = mRollbackStore.createStagedRollback(rollbackId, parentSessionId, userId, installerPackageName, packageSessionIds); installerPackageName, packageSessionIds, getExtensionVersions()); } else { rollback = mRollbackStore.createNonStagedRollback(rollbackId, userId, installerPackageName, packageSessionIds); installerPackageName, packageSessionIds, getExtensionVersions()); } mRollbacks.add(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 null if not found. Loading
services/core/java/com/android/server/rollback/RollbackStore.java +40 −5 Original line number Diff line number Diff line Loading @@ -21,12 +21,14 @@ import static android.os.UserHandle.USER_SYSTEM; import static com.android.server.rollback.Rollback.rollbackStateFromString; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.PackageManager; import android.content.pm.VersionedPackage; import android.content.rollback.PackageRollbackInfo; import android.content.rollback.PackageRollbackInfo.RestoreInfo; import android.content.rollback.RollbackInfo; import android.util.Slog; import android.util.SparseIntArray; import android.util.SparseLongArray; import com.android.internal.annotations.GuardedBy; Loading Loading @@ -171,6 +173,35 @@ class RollbackStore { 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 { JSONObject json = new JSONObject(); json.put("rollbackId", rollback.getRollbackId()); Loading @@ -195,10 +226,10 @@ class RollbackStore { * backupDir assigned. */ Rollback createNonStagedRollback(int rollbackId, int userId, String installerPackageName, int[] packageSessionIds) { int[] packageSessionIds, SparseIntArray extensionVersions) { File backupDir = new File(mRollbackDataDir, Integer.toString(rollbackId)); return new Rollback(rollbackId, backupDir, -1, userId, installerPackageName, packageSessionIds); packageSessionIds, extensionVersions); } /** Loading @@ -206,10 +237,11 @@ class RollbackStore { * backupDir assigned. */ 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)); return new Rollback(rollbackId, backupDir, stagedSessionId, userId, installerPackageName, packageSessionIds); packageSessionIds, extensionVersions); } /** Loading Loading @@ -267,6 +299,8 @@ class RollbackStore { dataJson.put("restoreUserDataInProgress", rollback.isRestoreUserDataInProgress()); dataJson.put("userId", rollback.getUserId()); dataJson.putOpt("installerPackageName", rollback.getInstallerPackageName()); dataJson.putOpt( "extensionVersions", extensionVersionsToJson(rollback.getExtensionVersions())); PrintWriter pw = new PrintWriter(new File(rollback.getBackupDir(), "rollback.json")); pw.println(dataJson.toString()); Loading Loading @@ -311,7 +345,8 @@ class RollbackStore { dataJson.getInt("apkSessionId"), dataJson.getBoolean("restoreUserDataInProgress"), dataJson.optInt("userId", USER_SYSTEM), dataJson.optString("installerPackageName", "")); dataJson.optString("installerPackageName", ""), extensionVersionsFromJson(dataJson.optJSONArray("extensionVersions"))); } private static JSONObject toJson(VersionedPackage pkg) throws JSONException { Loading
services/tests/servicestests/src/com/android/server/rollback/RollbackStoreTest.java +104 −6 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat; import android.content.pm.VersionedPackage; import android.content.rollback.PackageRollbackInfo; import android.util.SparseIntArray; import android.util.SparseLongArray; import com.google.common.truth.Correspondence; Loading Loading @@ -82,7 +83,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}," + "'versionRolledBackTo':{'packageName':'blah1','longVersionCode':50},'pendingBackups':" + "[59,1245,124544],'pendingRestores':[{'userId':498,'appId':32322,'seInfo':'wombles'}," Loading @@ -102,6 +103,28 @@ public class RollbackStoreTest { + "'restoreUserDataInProgress':true, 'userId':0," + "'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 public TemporaryFolder mFolder = new TemporaryFolder(); Loading @@ -118,7 +141,10 @@ public class RollbackStoreTest { @Test 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()) .isEqualTo(mFolder.getRoot().getAbsolutePath() + "/" + ID); Loading @@ -127,11 +153,16 @@ public class RollbackStoreTest { assertThat(rollback.info.getRollbackId()).isEqualTo(ID); assertThat(rollback.info.getPackages()).isEmpty(); assertThat(rollback.isEnabling()).isTrue(); assertThat(rollback.getExtensionVersions().toString()) .isEqualTo(extensionVersions.toString()); } @Test 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()) .isEqualTo(mFolder.getRoot().getAbsolutePath() + "/" + ID); Loading @@ -142,11 +173,17 @@ public class RollbackStoreTest { assertThat(rollback.info.getRollbackId()).isEqualTo(ID); assertThat(rollback.info.getPackages()).isEmpty(); assertThat(rollback.isEnabling()).isTrue(); assertThat(rollback.getExtensionVersions().toString()) .isEqualTo(extensionVersions.toString()); } @Test 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.info.getCausePackages().add(new VersionedPackage("com.made.up", 2)); Loading Loading @@ -194,9 +231,63 @@ public class RollbackStoreTest { 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 ArrayList<>(), new ArrayList<>(), false, false, new ArrayList<>(), 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 ArrayList<>(), new ArrayList<>(), false, false, new ArrayList<>(), 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 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.setRestoreUserDataInProgress(true); Loading Loading @@ -245,7 +336,7 @@ public class RollbackStoreTest { @Test public void saveAndDelete() { Rollback rollback = mRollbackStore.createNonStagedRollback(ID, USER, INSTALLER, null); Rollback rollback = mRollbackStore.createNonStagedRollback(ID, USER, INSTALLER, null, null); RollbackStore.saveRollback(rollback); Loading Loading @@ -293,6 +384,13 @@ public class RollbackStoreTest { assertThat(a.getUserId()).isEqualTo(b.getUserId()); 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) { Loading