From 72fb961cba8b6e86f962546162e82c8cfdd065f2 Mon Sep 17 00:00:00 2001 From: Richard Uhler Date: Mon, 4 Feb 2019 14:37:36 +0000 Subject: [PATCH 1/4] Wire up info for staged/apex rollbacks. Assuming we know if a rollback is staged or for apex, propagate that information properly to RollbackInfo and when executing the rollback. Test: atest RollbackTest Bug: 112431924 Change-Id: Ia4d800d7e946206e75fd559aa77146f0010e0615 --- .../android/server/rollback/RollbackData.java | 7 +++++++ .../rollback/RollbackManagerServiceImpl.java | 20 ++++++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/rollback/RollbackData.java b/services/core/java/com/android/server/rollback/RollbackData.java index 467bb28f57440..80d3c8358bea3 100644 --- a/services/core/java/com/android/server/rollback/RollbackData.java +++ b/services/core/java/com/android/server/rollback/RollbackData.java @@ -68,4 +68,11 @@ class RollbackData { this.backupDir = backupDir; this.stagedSessionId = stagedSessionId; } + + /** + * Whether the rollback is for rollback of a staged install. + */ + public boolean isStaged() { + return stagedSessionId != -1; + } } diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index 7885abe17c5bd..0d3348beb17e7 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -221,9 +221,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { List rollbacks = new ArrayList<>(); for (int i = 0; i < mAvailableRollbacks.size(); ++i) { RollbackData data = mAvailableRollbacks.get(i); - // TODO: Pass the correct value for isStaged instead of - // assuming always false. - rollbacks.add(new RollbackInfo(data.rollbackId, data.packages, false)); + rollbacks.add(new RollbackInfo(data.rollbackId, data.packages, data.isStaged())); } return new ParceledListSlice<>(rollbacks); } @@ -323,6 +321,10 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { PackageInstaller.SessionParams.MODE_FULL_INSTALL); parentParams.setAllowDowngrade(true); parentParams.setMultiPackage(); + if (data.isStaged()) { + parentParams.setStaged(); + } + int parentSessionId = packageInstaller.createSession(parentParams); PackageInstaller.Session parentSession = packageInstaller.openSession(parentSessionId); @@ -337,6 +339,12 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { } params.setInstallerPackageName(installerPackageName); params.setAllowDowngrade(true); + if (data.isStaged()) { + params.setStaged(); + } + if (info.isApex()) { + params.setInstallAsApex(); + } int sessionId = packageInstaller.createSession(params); PackageInstaller.Session session = packageInstaller.openSession(sessionId); @@ -376,11 +384,9 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { return; } - // TODO: Set the correct values for isStaged and - // committedSessionId. addRecentlyExecutedRollback(new RollbackInfo( - data.rollbackId, data.packages, false, causePackages, - PackageInstaller.SessionInfo.INVALID_ID)); + data.rollbackId, data.packages, data.isStaged(), + causePackages, parentSessionId)); sendSuccess(statusReceiver); Intent broadcast = new Intent(Intent.ACTION_ROLLBACK_COMMITTED); From b502afb18a423700a2dfcbe236441af5ed04ce6a Mon Sep 17 00:00:00 2001 From: Richard Uhler Date: Tue, 5 Feb 2019 12:16:34 +0000 Subject: [PATCH 2/4] MATCH_APEX when getting installed package version. Needed to get the installed package version for apex packages. Test: atest RollbackTest Bug: 112431924 Change-Id: I13f2649b05a25a80a4b84fe041c95b90fd7b51a0 --- .../com/android/server/rollback/RollbackManagerServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index 0d3348beb17e7..39eaa3a0fbd01 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -924,7 +924,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { PackageManager pm = mContext.getPackageManager(); PackageInfo pkgInfo = null; try { - pkgInfo = pm.getPackageInfo(packageName, 0); + pkgInfo = pm.getPackageInfo(packageName, PackageManager.MATCH_APEX); } catch (PackageManager.NameNotFoundException e) { return null; } From 7a5eeb1ae3ffbbb81f097d77e012136488e33aa2 Mon Sep 17 00:00:00 2001 From: Richard Uhler Date: Tue, 5 Feb 2019 12:51:48 +0000 Subject: [PATCH 3/4] Don't restore installer when rolling back APEX Because the package manager doesn't currently support getting the installer package for an apex. Test: atest RollbackTest Bug: 112431924 Change-Id: Ib53a54a3d089458a8e09f27bdf6eca2091995593 --- .../rollback/RollbackManagerServiceImpl.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index 39eaa3a0fbd01..85287ef9e6645 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -331,13 +331,18 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { for (PackageRollbackInfo info : data.packages) { PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( PackageInstaller.SessionParams.MODE_FULL_INSTALL); - String installerPackageName = pm.getInstallerPackageName(info.getPackageName()); - if (installerPackageName == null) { - sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE, - "Cannot find installer package"); - return; + // TODO: We can't get the installerPackageName for apex + // (b/123920130). Is it okay to ignore the installer package + // for apex? + if (!info.isApex()) { + String installerPackageName = pm.getInstallerPackageName(info.getPackageName()); + if (installerPackageName == null) { + sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE, + "Cannot find installer package"); + return; + } + params.setInstallerPackageName(installerPackageName); } - params.setInstallerPackageName(installerPackageName); params.setAllowDowngrade(true); if (data.isStaged()) { params.setStaged(); From 60ac706fdce0c5b86e989058efc68f96051fcfc4 Mon Sep 17 00:00:00 2001 From: Richard Uhler Date: Tue, 5 Feb 2019 13:25:39 +0000 Subject: [PATCH 4/4] Add isAvailable flag to RollbackData. To distinguish between rollbacks of staged sessions before and after the session has been applied. Bug: 112431924 Test: atest RollbackTest Change-Id: I93d6af4836933c0b551e17479ec896639ca0740e --- .../com/android/server/rollback/RollbackData.java | 11 ++++++++++- .../server/rollback/RollbackManagerServiceImpl.java | 13 ++++++++++--- .../com/android/server/rollback/RollbackStore.java | 8 +++++--- .../server/rollback/AppDataRollbackHelperTest.java | 2 +- 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/rollback/RollbackData.java b/services/core/java/com/android/server/rollback/RollbackData.java index 80d3c8358bea3..f45666574ed78 100644 --- a/services/core/java/com/android/server/rollback/RollbackData.java +++ b/services/core/java/com/android/server/rollback/RollbackData.java @@ -55,6 +55,14 @@ class RollbackData { */ public int stagedSessionId; + /** + * A flag to indicate whether the rollback should be considered available + * for use. This will always be true for rollbacks of non-staged sessions. + * For rollbacks of staged sessions, this is not set to true until after + * the staged session has been applied. + */ + public boolean isAvailable; + /** * Whether this Rollback is currently in progress. This field is true from the point * we commit a {@code PackageInstaller} session containing these packages to the point the @@ -63,10 +71,11 @@ class RollbackData { // NOTE: All accesses to this field are from the RollbackManager handler thread. public boolean inProgress = false; - RollbackData(int rollbackId, File backupDir, int stagedSessionId) { + RollbackData(int rollbackId, File backupDir, int stagedSessionId, boolean isAvailable) { this.rollbackId = rollbackId; this.backupDir = backupDir; this.stagedSessionId = stagedSessionId; + this.isAvailable = isAvailable; } /** diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index 85287ef9e6645..438e47964c5e7 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -221,7 +221,10 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { List rollbacks = new ArrayList<>(); for (int i = 0; i < mAvailableRollbacks.size(); ++i) { RollbackData data = mAvailableRollbacks.get(i); - rollbacks.add(new RollbackInfo(data.rollbackId, data.packages, data.isStaged())); + if (data.isAvailable) { + rollbacks.add(new RollbackInfo(data.rollbackId, + data.packages, data.isStaged())); + } } return new ParceledListSlice<>(rollbacks); } @@ -655,6 +658,10 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { Iterator iter = mAvailableRollbacks.iterator(); while (iter.hasNext()) { RollbackData data = iter.next(); + if (!data.isAvailable) { + continue; + } + if (!now.isBefore(data.timestamp.plusMillis(ROLLBACK_LIFETIME_DURATION_MILLIS))) { iter.remove(); mRollbackStore.deleteAvailableRollback(data); @@ -1064,7 +1071,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { ensureRollbackDataLoadedLocked(); for (int i = 0; i < mAvailableRollbacks.size(); ++i) { RollbackData data = mAvailableRollbacks.get(i); - if (getPackageRollbackInfo(data, packageName) != null) { + if (data.isAvailable && getPackageRollbackInfo(data, packageName) != null) { return data; } } @@ -1083,7 +1090,7 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { ensureRollbackDataLoadedLocked(); for (int i = 0; i < mAvailableRollbacks.size(); ++i) { RollbackData data = mAvailableRollbacks.get(i); - if (data.rollbackId == rollbackId) { + if (data.isAvailable && data.rollbackId == rollbackId) { return data; } } diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java index ff516902a5b35..1e45ba2e495cf 100644 --- a/services/core/java/com/android/server/rollback/RollbackStore.java +++ b/services/core/java/com/android/server/rollback/RollbackStore.java @@ -201,13 +201,13 @@ class RollbackStore { */ RollbackData createAvailableRollback(int rollbackId) throws IOException { File backupDir = new File(mAvailableRollbacksDir, Integer.toString(rollbackId)); - return new RollbackData(rollbackId, backupDir, -1); + return new RollbackData(rollbackId, backupDir, -1, true); } RollbackData createPendingStagedRollback(int rollbackId, int stagedSessionId) throws IOException { File backupDir = new File(mAvailableRollbacksDir, Integer.toString(rollbackId)); - return new RollbackData(rollbackId, backupDir, stagedSessionId); + return new RollbackData(rollbackId, backupDir, stagedSessionId, false); } /** @@ -247,6 +247,7 @@ class RollbackStore { dataJson.put("packages", toJson(data.packages)); dataJson.put("timestamp", data.timestamp.toString()); dataJson.put("stagedSessionId", data.stagedSessionId); + dataJson.put("isAvailable", data.isAvailable); PrintWriter pw = new PrintWriter(new File(data.backupDir, "rollback.json")); pw.println(dataJson.toString()); @@ -307,8 +308,9 @@ class RollbackStore { int rollbackId = dataJson.getInt("rollbackId"); int stagedSessionId = dataJson.getInt("stagedSessionId"); + boolean isAvailable = dataJson.getBoolean("isAvailable"); RollbackData data = new RollbackData(rollbackId, backupDir, - stagedSessionId); + stagedSessionId, isAvailable); data.packages.addAll(packageRollbackInfosFromJson(dataJson.getJSONArray("packages"))); data.timestamp = Instant.parse(dataJson.getString("timestamp")); return data; diff --git a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java index f1e6bc25dabfb..43e3eb0193b1f 100644 --- a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java @@ -80,7 +80,7 @@ public class AppDataRollbackHelperTest { } private static RollbackData createInProgressRollbackData(String packageName) { - RollbackData data = new RollbackData(1, new File("/does/not/exist"), -1); + RollbackData data = new RollbackData(1, new File("/does/not/exist"), -1, true); data.packages.add(new PackageRollbackInfo( new VersionedPackage(packageName, 1), new VersionedPackage(packageName, 1), new IntArray(), new ArrayList<>(), false));