Add support for rollback of multiPackage installs.
The RollbackManager APIs still need to be updated to expose information
about dependant rollbacks.
Test: atest RollbackTest, with multiPackage test now enabled.
Bug: 112431924
Change-Id: Ib05902aa2bc8b8e228ad6faf3d9418190c5bc946
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 2f37ac7b..8021265 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -93,6 +93,11 @@
@GuardedBy("mLock")
private final Map<Integer, RollbackData> mPendingRollbacks = new HashMap<>();
+ // Map from child session id's for enabled rollbacks to their
+ // corresponding parent session ids.
+ @GuardedBy("mLock")
+ private final Map<Integer, Integer> mChildSessions = new HashMap<>();
+
// Package rollback data available to be used for rolling back a package.
// This list is null until the rollback data has been loaded.
@GuardedBy("mLock")
@@ -771,16 +776,29 @@
Log.i(TAG, "Enabling rollback for install of " + packageName);
// Figure out the session id associated with this install.
- int sessionId = PackageInstaller.SessionInfo.INVALID_ID;
+ int parentSessionId = PackageInstaller.SessionInfo.INVALID_ID;
+ int childSessionId = PackageInstaller.SessionInfo.INVALID_ID;
PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
for (PackageInstaller.SessionInfo info : installer.getAllSessions()) {
- if (sessionMatchesForEnableRollback(info, installFlags, newPackageCodePath)) {
- // TODO: Check we only have one matching session?
- sessionId = info.getSessionId();
+ if (info.isMultiPackage()) {
+ for (int childId : info.getChildSessionIds()) {
+ PackageInstaller.SessionInfo child = installer.getSessionInfo(childId);
+ if (sessionMatchesForEnableRollback(child, installFlags, newPackageCodePath)) {
+ // TODO: Check we only have one matching session?
+ parentSessionId = info.getSessionId();
+ childSessionId = childId;
+ }
+ }
+ } else {
+ if (sessionMatchesForEnableRollback(info, installFlags, newPackageCodePath)) {
+ // TODO: Check we only have one matching session?
+ parentSessionId = info.getSessionId();
+ childSessionId = parentSessionId;
+ }
}
}
- if (sessionId == PackageInstaller.SessionInfo.INVALID_ID) {
+ if (parentSessionId == PackageInstaller.SessionInfo.INVALID_ID) {
Log.e(TAG, "Unable to find session id for enabled rollback.");
return false;
}
@@ -800,16 +818,28 @@
PackageRollbackInfo.PackageVersion installedVersion =
new PackageRollbackInfo.PackageVersion(installedPackage.getLongVersionCode());
- File backupDir;
+ PackageRollbackInfo info = new PackageRollbackInfo(
+ packageName, newVersion, installedVersion);
+
+ RollbackData data;
try {
- backupDir = Files.createTempDirectory(
- mAvailableRollbacksDir.toPath(), null).toFile();
+ synchronized (mLock) {
+ mChildSessions.put(childSessionId, parentSessionId);
+ data = mPendingRollbacks.get(parentSessionId);
+ if (data == null) {
+ File backupDir = Files.createTempDirectory(
+ mAvailableRollbacksDir.toPath(), null).toFile();
+ data = new RollbackData(backupDir);
+ mPendingRollbacks.put(parentSessionId, data);
+ }
+ data.packages.add(info);
+ }
} catch (IOException e) {
Log.e(TAG, "Unable to create rollback for " + packageName, e);
return false;
}
- File packageDir = new File(backupDir, packageName);
+ File packageDir = new File(data.backupDir, packageName);
packageDir.mkdirs();
try {
JSONObject json = new JSONObject();
@@ -835,13 +865,6 @@
return false;
}
- RollbackData data = new RollbackData(backupDir);
- data.packages.add(new PackageRollbackInfo(packageName, newVersion, installedVersion));
-
- synchronized (mLock) {
- mPendingRollbacks.put(sessionId, data);
- }
-
return true;
}
@@ -924,6 +947,10 @@
public void onFinished(int sessionId, boolean success) {
RollbackData data = null;
synchronized (mLock) {
+ Integer parentSessionId = mChildSessions.remove(sessionId);
+ if (parentSessionId != null) {
+ sessionId = parentSessionId;
+ }
data = mPendingRollbacks.remove(sessionId);
}
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 18fcecf..77cd9d8 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -190,6 +190,8 @@
RollbackManager rm = RollbackTestUtils.getRollbackManager();
+ // TODO: Test this with multi-package rollback, not just single
+ // package rollback.
// Prep installation of TEST_APP_A
RollbackTestUtils.uninstall(TEST_APP_A);
RollbackTestUtils.install("RollbackTestAppAv1.apk", false);
@@ -511,7 +513,7 @@
* TODO: Stop ignoring this test once support for multi-package rollback
* is implemented.
*/
- @Ignore @Test
+ @Test
public void testMultiPackage() throws Exception {
try {
RollbackTestUtils.adoptShellPermissionIdentity(