diff options
| author | 2020-06-03 09:57:19 +0000 | |
|---|---|---|
| committer | 2020-06-03 09:57:19 +0000 | |
| commit | 742ba7a5b50a2d8ed0097ff6e70ce18742fd9c24 (patch) | |
| tree | 11a24fcb395fa768ceacf4e290ad3ae79d4534b2 | |
| parent | 7b3cc67d341f952fddd05875302318f979fa648b (diff) | |
| parent | 992b637327aeea3e5fddf3847ef6c7d51ee5d717 (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.java | 48 |
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 { |