Merge "Persist failure reason for staged installs across checkpoint reboots" into rvc-dev am: 742ba7a5b5
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/11408099 Change-Id: I42202ad9dce14326db4d49eee1df4dd675588fce
This commit is contained in:
committed by
Automerger Merge Worker
commit
982be73074
@@ -77,7 +77,11 @@ import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
|
|||||||
import com.android.server.pm.parsing.pkg.ParsedPackage;
|
import com.android.server.pm.parsing.pkg.ParsedPackage;
|
||||||
import com.android.server.rollback.WatchdogRollbackLogger;
|
import com.android.server.rollback.WatchdogRollbackLogger;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -102,6 +106,9 @@ public class StagingManager {
|
|||||||
private final PreRebootVerificationHandler mPreRebootVerificationHandler;
|
private final PreRebootVerificationHandler mPreRebootVerificationHandler;
|
||||||
private final Supplier<PackageParser2> mPackageParserSupplier;
|
private final Supplier<PackageParser2> mPackageParserSupplier;
|
||||||
|
|
||||||
|
private final File mFailureReasonFile = new File("/metadata/staged-install/failure_reason.txt");
|
||||||
|
private String mFailureReason;
|
||||||
|
|
||||||
@GuardedBy("mStagedSessions")
|
@GuardedBy("mStagedSessions")
|
||||||
private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
|
private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
|
||||||
|
|
||||||
@@ -125,6 +132,12 @@ public class StagingManager {
|
|||||||
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
|
||||||
mPreRebootVerificationHandler = new PreRebootVerificationHandler(
|
mPreRebootVerificationHandler = new PreRebootVerificationHandler(
|
||||||
BackgroundThread.get().getLooper());
|
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.
|
// Reverts apex sessions and user data (if checkpoint is supported). Also reboots the device.
|
||||||
private void abortCheckpoint(String errorMsg) {
|
private void abortCheckpoint(int sessionId, String errorMsg) {
|
||||||
Slog.e(TAG, "Aborting checkpoint: " + errorMsg);
|
String failureReason = "Failed to install sessionId: " + sessionId + " Error: " + errorMsg;
|
||||||
|
Slog.e(TAG, failureReason);
|
||||||
try {
|
try {
|
||||||
if (supportsCheckpoint() && needsCheckpoint()) {
|
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
|
// Only revert apex sessions if device supports updating apex
|
||||||
if (mApexManager.isApexSupported()) {
|
if (mApexManager.isApexSupported()) {
|
||||||
mApexManager.revertActiveSessions();
|
mApexManager.revertActiveSessions();
|
||||||
@@ -592,14 +614,12 @@ public class StagingManager {
|
|||||||
// If checkpoint is supported, then we only resume sessions if we are in checkpointing
|
// If checkpoint is supported, then we only resume sessions if we are in checkpointing
|
||||||
// mode. If not, we fail all sessions.
|
// mode. If not, we fail all sessions.
|
||||||
if (supportsCheckpoint() && !needsCheckpoint()) {
|
if (supportsCheckpoint() && !needsCheckpoint()) {
|
||||||
// TODO(b/146343545): Persist failure reason across checkpoint reboot
|
String errorMsg = "Reverting back to safe state. Marking " + session.sessionId
|
||||||
Slog.d(TAG, "Reverting back to safe state. Marking " + session.sessionId
|
+ " as failed";
|
||||||
+ " as failed.");
|
if (!TextUtils.isEmpty(mFailureReason)) {
|
||||||
String errorMsg = "Reverting back to safe state";
|
errorMsg = errorMsg + ": " + mFailureReason;
|
||||||
if (!TextUtils.isEmpty(mNativeFailureReason)) {
|
|
||||||
errorMsg = "Entered fs-rollback mode and reverted session due to crashing "
|
|
||||||
+ "native process: " + mNativeFailureReason;
|
|
||||||
}
|
}
|
||||||
|
Slog.d(TAG, errorMsg);
|
||||||
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_UNKNOWN, errorMsg);
|
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_UNKNOWN, errorMsg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -624,7 +644,7 @@ public class StagingManager {
|
|||||||
+ "supposed to be activated";
|
+ "supposed to be activated";
|
||||||
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
|
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
|
||||||
errorMsg);
|
errorMsg);
|
||||||
abortCheckpoint(errorMsg);
|
abortCheckpoint(session.sessionId, errorMsg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isApexSessionFailed(apexSessionInfo)) {
|
if (isApexSessionFailed(apexSessionInfo)) {
|
||||||
@@ -636,7 +656,7 @@ public class StagingManager {
|
|||||||
}
|
}
|
||||||
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
|
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
|
||||||
errorMsg);
|
errorMsg);
|
||||||
abortCheckpoint(errorMsg);
|
abortCheckpoint(session.sessionId, errorMsg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!apexSessionInfo.isActivated && !apexSessionInfo.isSuccess) {
|
if (!apexSessionInfo.isActivated && !apexSessionInfo.isSuccess) {
|
||||||
@@ -647,7 +667,7 @@ public class StagingManager {
|
|||||||
+ "didn't activate nor fail. Marking it as failed anyway.";
|
+ "didn't activate nor fail. Marking it as failed anyway.";
|
||||||
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
|
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
|
||||||
errorMsg);
|
errorMsg);
|
||||||
abortCheckpoint(errorMsg);
|
abortCheckpoint(session.sessionId, errorMsg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -664,7 +684,7 @@ public class StagingManager {
|
|||||||
installApksInSession(session);
|
installApksInSession(session);
|
||||||
} catch (PackageManagerException e) {
|
} catch (PackageManagerException e) {
|
||||||
session.setStagedSessionFailed(e.error, e.getMessage());
|
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 checkpoint is not supported, we have to handle failure for one staged session.
|
||||||
if (!hasApex) {
|
if (!hasApex) {
|
||||||
@@ -1189,6 +1209,8 @@ public class StagingManager {
|
|||||||
ctx.unregisterReceiver(this);
|
ctx.unregisterReceiver(this);
|
||||||
}
|
}
|
||||||
}, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
|
}, new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
|
||||||
|
|
||||||
|
mFailureReasonFile.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class LocalIntentReceiverAsync {
|
private static class LocalIntentReceiverAsync {
|
||||||
|
|||||||
Reference in New Issue
Block a user