From 3fa0ce99ac29df436d1f69b520492178d255d6c2 Mon Sep 17 00:00:00 2001 From: JW Wang Date: Fri, 20 Dec 2019 14:34:40 +0800 Subject: [PATCH] Enable a new rollback only when all child sessions succeeded (1/n) Don't enable a new rollback until all its child sessions are notified with success by SessionCallback#onFinished. This change allows us to delete/remove a new rollback if any of its child sessions failed before enabling it. Bug: 134652027 Test: atest RollbackTest Change-Id: Ie7cee8b0998a1df381a83219988a3876629fbcbb --- .../rollback/RollbackManagerServiceImpl.java | 50 +++++++++++++++---- 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java index 9a65ae6dba4dc..c21c0a99f822d 100644 --- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java +++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java @@ -1089,19 +1089,28 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { if (LOCAL_LOGV) { Slog.v(TAG, "SessionCallback.onFinished id=" + sessionId + " success=" + success); } - NewRollback newRollback; - synchronized (mLock) { - newRollback = getNewRollbackForPackageSessionLocked(sessionId); - if (newRollback != null) { - mNewRollbacks.remove(newRollback); - } - } - if (newRollback != null) { - Rollback rollback = completeEnableRollback(newRollback, success); - if (rollback != null && !rollback.isStaged()) { - makeRollbackAvailable(rollback); + if (success) { + NewRollback newRollback; + synchronized (mLock) { + newRollback = getNewRollbackForPackageSessionLocked(sessionId); + if (newRollback != null && newRollback.notifySessionWithSuccess()) { + mNewRollbacks.remove(newRollback); + } else { + // Not all child sessions finished with success. + // Don't enable the rollback yet. + newRollback = null; + } } + + if (newRollback != null) { + Rollback rollback = completeEnableRollback(newRollback, success); + if (rollback != null && !rollback.isStaged()) { + makeRollbackAvailable(rollback); + } + } + } else { + // TODO: delete rollbacks for this failed session } // Clear the queue so it will never be leaked to next tests. @@ -1251,6 +1260,14 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { @GuardedBy("mNewRollbackLock") private boolean mIsCancelled = false; + /** + * The number of sessions in the install which are notified with success by + * {@link PackageInstaller.SessionCallback#onFinished(int, boolean)}. + * This NewRollback will be enabled only after all child sessions finished with success. + */ + @GuardedBy("mNewRollbackLock") + private int mNumPackageSessionsWithSuccess; + private final Object mNewRollbackLock = new Object(); NewRollback(Rollback rollback, int[] packageSessionIds) { @@ -1322,6 +1339,17 @@ class RollbackManagerServiceImpl extends IRollbackManager.Stub { int getPackageSessionIdCount() { return mPackageSessionIds.length; } + + /** + * Called when a child session finished with success. + * Returns true when all child sessions are notified with success. This NewRollback will be + * enabled only after all child sessions finished with success. + */ + boolean notifySessionWithSuccess() { + synchronized (mNewRollbackLock) { + return ++mNumPackageSessionsWithSuccess == mPackageSessionIds.length; + } + } } @GuardedBy("mLock")