Merge changes I5c190938,I9abec5d2,If1007966 into rvc-qpr-dev
* changes: [DO NOT MERGE] Prevent extra sessions owned by staged install from living across restarts Prevent exceptions during staged install from crashing system server Prevent exceptions in pre-reboot verification from crashing system server
This commit is contained in:
committed by
Android (Google) Code Review
commit
24038f61c5
@@ -393,6 +393,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
|
|||||||
Slog.w(TAG, "Abandoning old session created at "
|
Slog.w(TAG, "Abandoning old session created at "
|
||||||
+ session.createdMillis);
|
+ session.createdMillis);
|
||||||
valid = false;
|
valid = false;
|
||||||
|
} else if (isExtraSessionForStagedInstall(session)) {
|
||||||
|
valid = false;
|
||||||
} else {
|
} else {
|
||||||
valid = true;
|
valid = true;
|
||||||
}
|
}
|
||||||
@@ -423,6 +425,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extra sessions are created during staged install on temporary basis. They should not be
|
||||||
|
// allowed to live across system server restart.
|
||||||
|
private boolean isExtraSessionForStagedInstall(PackageInstallerSession session) {
|
||||||
|
return (session.params.installFlags & PackageManager.INSTALL_DRY_RUN) != 0
|
||||||
|
|| (session.params.installFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
@GuardedBy("mSessions")
|
@GuardedBy("mSessions")
|
||||||
private void addHistoricalSessionLocked(PackageInstallerSession session) {
|
private void addHistoricalSessionLocked(PackageInstallerSession session) {
|
||||||
CharArrayWriter writer = new CharArrayWriter();
|
CharArrayWriter writer = new CharArrayWriter();
|
||||||
|
|||||||
@@ -564,7 +564,8 @@ public class StagingManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resumeSession(@NonNull PackageInstallerSession session) {
|
private void resumeSession(@NonNull PackageInstallerSession session)
|
||||||
|
throws PackageManagerException {
|
||||||
Slog.d(TAG, "Resuming session " + session.sessionId);
|
Slog.d(TAG, "Resuming session " + session.sessionId);
|
||||||
|
|
||||||
final boolean hasApex = sessionContainsApex(session);
|
final boolean hasApex = sessionContainsApex(session);
|
||||||
@@ -628,10 +629,8 @@ public class StagingManager {
|
|||||||
if (apexSessionInfo == null) {
|
if (apexSessionInfo == null) {
|
||||||
final String errorMsg = "apexd did not know anything about a staged session "
|
final String errorMsg = "apexd did not know anything about a staged session "
|
||||||
+ "supposed to be activated";
|
+ "supposed to be activated";
|
||||||
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
|
throw new PackageManagerException(
|
||||||
errorMsg);
|
SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMsg);
|
||||||
abortCheckpoint(session.sessionId, errorMsg);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (isApexSessionFailed(apexSessionInfo)) {
|
if (isApexSessionFailed(apexSessionInfo)) {
|
||||||
String errorMsg = "APEX activation failed. Check logcat messages from apexd "
|
String errorMsg = "APEX activation failed. Check logcat messages from apexd "
|
||||||
@@ -640,10 +639,8 @@ public class StagingManager {
|
|||||||
errorMsg = "Session reverted due to crashing native process: "
|
errorMsg = "Session reverted due to crashing native process: "
|
||||||
+ mNativeFailureReason;
|
+ mNativeFailureReason;
|
||||||
}
|
}
|
||||||
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
|
throw new PackageManagerException(
|
||||||
errorMsg);
|
SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMsg);
|
||||||
abortCheckpoint(session.sessionId, errorMsg);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (!apexSessionInfo.isActivated && !apexSessionInfo.isSuccess) {
|
if (!apexSessionInfo.isActivated && !apexSessionInfo.isSuccess) {
|
||||||
// Apexd did not apply the session for some unknown reason. There is no
|
// Apexd did not apply the session for some unknown reason. There is no
|
||||||
@@ -651,42 +648,20 @@ public class StagingManager {
|
|||||||
// it as failed.
|
// it as failed.
|
||||||
final String errorMsg = "Staged session " + session.sessionId + "at boot "
|
final String errorMsg = "Staged session " + session.sessionId + "at boot "
|
||||||
+ "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,
|
throw new PackageManagerException(
|
||||||
errorMsg);
|
SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMsg);
|
||||||
abortCheckpoint(session.sessionId, errorMsg);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Handle apk and apk-in-apex installation
|
// Handle apk and apk-in-apex installation
|
||||||
try {
|
if (hasApex) {
|
||||||
if (hasApex) {
|
checkInstallationOfApkInApexSuccessful(session);
|
||||||
checkInstallationOfApkInApexSuccessful(session);
|
snapshotAndRestoreForApexSession(session);
|
||||||
snapshotAndRestoreForApexSession(session);
|
Slog.i(TAG, "APEX packages in session " + session.sessionId
|
||||||
Slog.i(TAG, "APEX packages in session " + session.sessionId
|
+ " were successfully activated. Proceeding with APK packages, if any");
|
||||||
+ " were successfully activated. Proceeding with APK packages, if any");
|
|
||||||
}
|
|
||||||
// The APEX part of the session is activated, proceed with the installation of APKs.
|
|
||||||
Slog.d(TAG, "Installing APK packages in session " + session.sessionId);
|
|
||||||
installApksInSession(session);
|
|
||||||
} catch (PackageManagerException e) {
|
|
||||||
session.setStagedSessionFailed(e.error, e.getMessage());
|
|
||||||
abortCheckpoint(session.sessionId, e.getMessage());
|
|
||||||
|
|
||||||
// If checkpoint is not supported, we have to handle failure for one staged session.
|
|
||||||
if (!hasApex) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mApexManager.revertActiveSessions()) {
|
|
||||||
Slog.e(TAG, "Failed to abort APEXd session");
|
|
||||||
} else {
|
|
||||||
Slog.e(TAG,
|
|
||||||
"Successfully aborted apexd session. Rebooting device in order to revert "
|
|
||||||
+ "to the previous state of APEXd.");
|
|
||||||
mPowerManager.reboot(null);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
// The APEX part of the session is activated, proceed with the installation of APKs.
|
||||||
|
Slog.d(TAG, "Installing APK packages in session " + session.sessionId);
|
||||||
|
installApksInSession(session);
|
||||||
|
|
||||||
Slog.d(TAG, "Marking session " + session.sessionId + " as applied");
|
Slog.d(TAG, "Marking session " + session.sessionId + " as applied");
|
||||||
session.setStagedSessionApplied();
|
session.setStagedSessionApplied();
|
||||||
@@ -722,6 +697,25 @@ public class StagingManager {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onInstallationFailure(PackageInstallerSession session, PackageManagerException e) {
|
||||||
|
session.setStagedSessionFailed(e.error, e.getMessage());
|
||||||
|
abortCheckpoint(session.sessionId, e.getMessage());
|
||||||
|
|
||||||
|
// If checkpoint is not supported, we have to handle failure for one staged session.
|
||||||
|
if (!sessionContainsApex(session)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mApexManager.revertActiveSessions()) {
|
||||||
|
Slog.e(TAG, "Failed to abort APEXd session");
|
||||||
|
} else {
|
||||||
|
Slog.e(TAG,
|
||||||
|
"Successfully aborted apexd session. Rebooting device in order to revert "
|
||||||
|
+ "to the previous state of APEXd.");
|
||||||
|
mPowerManager.reboot(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private PackageInstallerSession createAndWriteApkSession(
|
private PackageInstallerSession createAndWriteApkSession(
|
||||||
@NonNull PackageInstallerSession originalSession, boolean preReboot)
|
@NonNull PackageInstallerSession originalSession, boolean preReboot)
|
||||||
@@ -1072,6 +1066,26 @@ public class StagingManager {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure that there is no active apex session staged in apexd for the given session.
|
||||||
|
*
|
||||||
|
* @return returns true if it is ensured that there is no active apex session, otherwise false
|
||||||
|
*/
|
||||||
|
private boolean ensureActiveApexSessionIsAborted(PackageInstallerSession session) {
|
||||||
|
if (!sessionContainsApex(session)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
final ApexSessionInfo apexSession = mApexManager.getStagedSessionInfo(session.sessionId);
|
||||||
|
if (apexSession == null || isApexSessionFinalized(apexSession)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return mApexManager.abortStagedSession(session.sessionId);
|
||||||
|
} catch (PackageManagerException ignore) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isApexSessionFinalized(ApexSessionInfo session) {
|
private boolean isApexSessionFinalized(ApexSessionInfo session) {
|
||||||
/* checking if the session is in a final state, i.e., not active anymore */
|
/* checking if the session is in a final state, i.e., not active anymore */
|
||||||
return session.isUnknown || session.isActivationFailed || session.isSuccess
|
return session.isUnknown || session.isActivationFailed || session.isSuccess
|
||||||
@@ -1165,7 +1179,16 @@ public class StagingManager {
|
|||||||
} else {
|
} else {
|
||||||
// Session had already being marked ready. Start the checks to verify if there is any
|
// Session had already being marked ready. Start the checks to verify if there is any
|
||||||
// follow-up work.
|
// follow-up work.
|
||||||
resumeSession(session);
|
try {
|
||||||
|
resumeSession(session);
|
||||||
|
} catch (PackageManagerException e) {
|
||||||
|
onInstallationFailure(session, e);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Slog.e(TAG, "Staged install failed due to unhandled exception", e);
|
||||||
|
onInstallationFailure(session, new PackageManagerException(
|
||||||
|
SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
|
||||||
|
"Staged install failed due to unhandled exception: " + e));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1303,19 +1326,26 @@ public class StagingManager {
|
|||||||
onPreRebootVerificationComplete(sessionId);
|
onPreRebootVerificationComplete(sessionId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (msg.what) {
|
try {
|
||||||
case MSG_PRE_REBOOT_VERIFICATION_START:
|
switch (msg.what) {
|
||||||
handlePreRebootVerification_Start(session);
|
case MSG_PRE_REBOOT_VERIFICATION_START:
|
||||||
break;
|
handlePreRebootVerification_Start(session);
|
||||||
case MSG_PRE_REBOOT_VERIFICATION_APEX:
|
break;
|
||||||
handlePreRebootVerification_Apex(session);
|
case MSG_PRE_REBOOT_VERIFICATION_APEX:
|
||||||
break;
|
handlePreRebootVerification_Apex(session);
|
||||||
case MSG_PRE_REBOOT_VERIFICATION_APK:
|
break;
|
||||||
handlePreRebootVerification_Apk(session);
|
case MSG_PRE_REBOOT_VERIFICATION_APK:
|
||||||
break;
|
handlePreRebootVerification_Apk(session);
|
||||||
case MSG_PRE_REBOOT_VERIFICATION_END:
|
break;
|
||||||
handlePreRebootVerification_End(session);
|
case MSG_PRE_REBOOT_VERIFICATION_END:
|
||||||
break;
|
handlePreRebootVerification_End(session);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
Slog.e(TAG, "Pre-reboot verification failed due to unhandled exception", e);
|
||||||
|
onPreRebootVerificationFailure(session,
|
||||||
|
SessionInfo.STAGED_SESSION_ACTIVATION_FAILED,
|
||||||
|
"Pre-reboot verification failed due to unhandled exception: " + e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1352,6 +1382,17 @@ public class StagingManager {
|
|||||||
obtainMessage(MSG_PRE_REBOOT_VERIFICATION_START, sessionId, 0).sendToTarget();
|
obtainMessage(MSG_PRE_REBOOT_VERIFICATION_START, sessionId, 0).sendToTarget();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onPreRebootVerificationFailure(PackageInstallerSession session,
|
||||||
|
@SessionInfo.StagedSessionErrorCode int errorCode, String errorMessage) {
|
||||||
|
if (!ensureActiveApexSessionIsAborted(session)) {
|
||||||
|
Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
|
||||||
|
// Safe to ignore active apex session abortion failure since session will be marked
|
||||||
|
// failed on next step and staging directory for session will be deleted.
|
||||||
|
}
|
||||||
|
session.setStagedSessionFailed(errorCode, errorMessage);
|
||||||
|
onPreRebootVerificationComplete(session.sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
// Things to do when pre-reboot verification completes for a particular sessionId
|
// Things to do when pre-reboot verification completes for a particular sessionId
|
||||||
private void onPreRebootVerificationComplete(int sessionId) {
|
private void onPreRebootVerificationComplete(int sessionId) {
|
||||||
// Remove it from mVerificationRunning so that verification is considered complete
|
// Remove it from mVerificationRunning so that verification is considered complete
|
||||||
|
|||||||
Reference in New Issue
Block a user