summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Mohammad Samiul Islam <samiul@google.com> 2020-06-03 09:57:19 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-06-03 09:57:19 +0000
commit742ba7a5b50a2d8ed0097ff6e70ce18742fd9c24 (patch)
tree11a24fcb395fa768ceacf4e290ad3ae79d4534b2
parent7b3cc67d341f952fddd05875302318f979fa648b (diff)
parent992b637327aeea3e5fddf3847ef6c7d51ee5d717 (diff)
Merge "Persist failure reason for staged installs across checkpoint reboots" into rvc-dev
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java48
1 files changed, 35 insertions, 13 deletions
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 79805e3b42ae..8ccf837f64dc 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -77,7 +77,11 @@ import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.rollback.WatchdogRollbackLogger;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -102,6 +106,9 @@ public class StagingManager {
private final PreRebootVerificationHandler mPreRebootVerificationHandler;
private final Supplier<PackageParser2> mPackageParserSupplier;
+ private final File mFailureReasonFile = new File("/metadata/staged-install/failure_reason.txt");
+ private String mFailureReason;
+
@GuardedBy("mStagedSessions")
private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
@@ -125,6 +132,12 @@ public class StagingManager {
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
mPreRebootVerificationHandler = new PreRebootVerificationHandler(
BackgroundThread.get().getLooper());
+
+ if (mFailureReasonFile.exists()) {
+ try (BufferedReader reader = new BufferedReader(new FileReader(mFailureReasonFile))) {
+ mFailureReason = reader.readLine();
+ } catch (Exception ignore) { }
+ }
}
/**
@@ -383,10 +396,19 @@ public class StagingManager {
}
// Reverts apex sessions and user data (if checkpoint is supported). Also reboots the device.
- private void abortCheckpoint(String errorMsg) {
- Slog.e(TAG, "Aborting checkpoint: " + errorMsg);
+ private void abortCheckpoint(int sessionId, String errorMsg) {
+ String failureReason = "Failed to install sessionId: " + sessionId + " Error: " + errorMsg;
+ Slog.e(TAG, failureReason);
try {
if (supportsCheckpoint() && needsCheckpoint()) {
+ // Store failure reason for next reboot
+ try (BufferedWriter writer =
+ new BufferedWriter(new FileWriter(mFailureReasonFile))) {
+ writer.write(failureReason);
+ } catch (Exception e) {
+ Slog.w(TAG, "Failed to save failure reason: ", e);
+ }
+
// Only revert apex sessions if device supports updating apex
if (mApexManager.isApexSupported()) {
mApexManager.revertActiveSessions();
@@ -592,14 +614,12 @@ public class StagingManager {
// If checkpoint is supported, then we only resume sessions if we are in checkpointing
// mode. If not, we fail all sessions.
if (supportsCheckpoint() && !needsCheckpoint()) {
- // TODO(b/146343545): Persist failure reason across checkpoint reboot
- Slog.d(TAG, "Reverting back to safe state. Marking " + session.sessionId
- + " as failed.");
- String errorMsg = "Reverting back to safe state";
- if (!TextUtils.isEmpty(mNativeFailureReason)) {
- errorMsg = "Entered fs-rollback mode and reverted session due to crashing "
- + "native process: " + mNativeFailureReason;
+ String errorMsg = "Reverting back to safe state. Marking " + session.sessionId
+ + " as failed";
+ if (!TextUtils.isEmpty(mFailureReason)) {
+ errorMsg = errorMsg + ": " + mFailureReason;
}
+ Slog.d(TAG, errorMsg);
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_UNKNOWN, errorMsg);
return;
}
@@ -624,7 +644,7 @@ public class StagingManager {
+ "supposed to be activated";
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
errorMsg);
- abortCheckpoint(errorMsg);
+ abortCheckpoint(session.sessionId, errorMsg);
return;
}
if (isApexSessionFailed(apexSessionInfo)) {
@@ -636,7 +656,7 @@ public class StagingManager {
}
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
errorMsg);
- abortCheckpoint(errorMsg);
+ abortCheckpoint(session.sessionId, errorMsg);
return;
}
if (!apexSessionInfo.isActivated && !apexSessionInfo.isSuccess) {
@@ -647,7 +667,7 @@ public class StagingManager {
+ "didn't activate nor fail. Marking it as failed anyway.";
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
errorMsg);
- abortCheckpoint(errorMsg);
+ abortCheckpoint(session.sessionId, errorMsg);
return;
}
}
@@ -664,7 +684,7 @@ public class StagingManager {
installApksInSession(session);
} catch (PackageManagerException e) {
session.setStagedSessionFailed(e.error, e.getMessage());
- abortCheckpoint(e.getMessage());
+ abortCheckpoint(session.sessionId, e.getMessage());
// If checkpoint is not supported, we have to handle failure for one staged session.
if (!hasApex) {
@@ -1189,6 +1209,8 @@ public class StagingManager {
ctx.unregisterReceiver(this);
}
}, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+
+ mFailureReasonFile.delete();
}
private static class LocalIntentReceiverAsync {