summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Zimuzo <zezeozue@google.com> 2019-05-16 18:09:23 +0100
committer Zimuzo <zezeozue@google.com> 2019-05-18 12:31:07 +0100
commit8d231b4c6dc5bd46ecd207ddd22c5374cc68c39c (patch)
tree8a87876f9bd62d47ec5890af20347cd7951c2a66
parent0ab517141f1828ec14a5b0071bdea0a60b873f71 (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.java24
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);