diff options
| author | 2019-05-16 18:09:23 +0100 | |
|---|---|---|
| committer | 2019-05-18 12:31:07 +0100 | |
| commit | 8d231b4c6dc5bd46ecd207ddd22c5374cc68c39c (patch) | |
| tree | 8a87876f9bd62d47ec5890af20347cd7951c2a66 | |
| parent | 0ab517141f1828ec14a5b0071bdea0a60b873f71 (diff) | |
Fix handling multiple staged rollback sessions ready signal
After we stage a session for rollback, we need to wait for the
session to be ready and then reboot. To ensure we don't miss the
ready signal, we register a BroadcastReceiver to listen to session changes
and also check for session ready right away. This caused a race condition
where we may handle post-ready twice. This caused a crash because we
attempt to unregister the receiver twice, it's also a problem because
we could log the same event twice.
Now, we store the rollback ids we are about to handle and ensure we never
handle post-ready more than once.
Test: Manual test && atest StagedRollbackTest
Bug: 132866890
Change-Id: I5187ff20fb83b29f7a00a28bf6ad8105ca4f0067
| -rw-r--r-- | services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java | 24 |
1 files changed, 22 insertions, 2 deletions
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java index bcef66ce2a53..da1c413f05da 100644 --- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java +++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java @@ -34,10 +34,12 @@ import android.os.HandlerThread; import android.os.PowerManager; import android.os.SystemProperties; import android.text.TextUtils; +import android.util.ArraySet; import android.util.Slog; import android.util.StatsLog; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import com.android.server.PackageWatchdog; import com.android.server.PackageWatchdog.PackageHealthObserver; import com.android.server.PackageWatchdog.PackageHealthObserverImpact; @@ -50,6 +52,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.concurrent.TimeUnit; /** @@ -71,6 +74,9 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve private final Context mContext; private final Handler mHandler; private final File mLastStagedRollbackIdFile; + // Staged rollback ids that have been committed but their session is not yet ready + @GuardedBy("mPendingStagedRollbackIds") + private final Set<Integer> mPendingStagedRollbackIds = new ArraySet<>(); // this field is initialized in the c'tor and then only accessed from mHandler thread, so // no need to guard with a lock private long mNumberOfNativeCrashPollsRemaining; @@ -120,6 +126,9 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve if (status == RollbackManager.STATUS_SUCCESS) { if (rollback.isStaged()) { int rollbackId = rollback.getRollbackId(); + synchronized (mPendingStagedRollbackIds) { + mPendingStagedRollbackIds.add(rollbackId); + } BroadcastReceiver listener = listenForStagedSessionReady(rollbackManager, rollbackId, moduleMetadataPackage); @@ -289,14 +298,15 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve && (sessionId != PackageInstaller.SessionInfo.INVALID_ID)) { PackageInstaller.SessionInfo sessionInfo = packageInstaller.getSessionInfo(sessionId); - if (sessionInfo.isStagedSessionReady()) { + if (sessionInfo.isStagedSessionReady() && markStagedSessionHandled(rollbackId)) { mContext.unregisterReceiver(listener); saveLastStagedRollbackId(rollbackId); logEvent(moduleMetadataPackage, StatsLog .WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_BOOT_TRIGGERED); mContext.getSystemService(PowerManager.class).reboot("Rollback staged install"); - } else if (sessionInfo.isStagedSessionFailed()) { + } else if (sessionInfo.isStagedSessionFailed() + && markStagedSessionHandled(rollbackId)) { logEvent(moduleMetadataPackage, StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE); mContext.unregisterReceiver(listener); @@ -305,6 +315,16 @@ public final class RollbackPackageHealthObserver implements PackageHealthObserve } } + /** + * Returns {@code true} if staged session associated with {@code rollbackId} was marked + * as handled, {@code false} if already handled. + */ + private boolean markStagedSessionHandled(int rollbackId) { + synchronized (mPendingStagedRollbackIds) { + return mPendingStagedRollbackIds.remove(rollbackId); + } + } + private void saveLastStagedRollbackId(int stagedRollbackId) { try { FileOutputStream fos = new FileOutputStream(mLastStagedRollbackIdFile); |