Populate error message in case APK part of staged install fails

Bug: 136548037
Test: atest CtsStagedInstallHostTestCases
Change-Id: I3fa3dfdf9f920f870f07d55782944043e1afbe2a
This commit is contained in:
Nikita Ioffe
2019-07-15 13:28:11 +01:00
parent 3926904406
commit c2b87a9c1d

View File

@@ -242,11 +242,11 @@ public class StagingManager {
} }
if (sessionContainsApk(session)) { if (sessionContainsApk(session)) {
if (!installApksInSession(session, /* preReboot */ true)) { try {
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, installApksInSession(session, /* preReboot */ true);
"APK verification failed. Check logcat messages for "
+ "more information.");
// TODO(b/118865310): abort the session on apexd. // TODO(b/118865310): abort the session on apexd.
} catch (PackageManagerException e) {
session.setStagedSessionFailed(e.error, e.getMessage());
return; return;
} }
} }
@@ -315,7 +315,7 @@ public class StagingManager {
} }
private void resumeSession(@NonNull PackageInstallerSession session) { private void resumeSession(@NonNull PackageInstallerSession session) {
boolean hasApex = sessionContainsApex(session); final boolean hasApex = sessionContainsApex(session);
if (hasApex) { if (hasApex) {
// Check with apexservice whether the apex packages have been activated. // Check with apexservice whether the apex packages have been activated.
ApexSessionInfo apexSessionInfo = mApexManager.getStagedSessionInfo(session.sessionId); ApexSessionInfo apexSessionInfo = mApexManager.getStagedSessionInfo(session.sessionId);
@@ -350,10 +350,10 @@ public class StagingManager {
} }
} }
// The APEX part of the session is activated, proceed with the installation of APKs. // The APEX part of the session is activated, proceed with the installation of APKs.
if (!installApksInSession(session, /* preReboot */ false)) { try {
session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, installApksInSession(session, /* preReboot */ false);
"Staged installation of APKs failed. Check logcat messages for" } catch (PackageManagerException e) {
+ "more information."); session.setStagedSessionFailed(e.error, e.getMessage());
if (!hasApex) { if (!hasApex) {
return; return;
@@ -388,16 +388,22 @@ public class StagingManager {
return ret; return ret;
} }
@NonNull
private PackageInstallerSession createAndWriteApkSession( private PackageInstallerSession createAndWriteApkSession(
@NonNull PackageInstallerSession originalSession, boolean preReboot) { @NonNull PackageInstallerSession originalSession, boolean preReboot)
throws PackageManagerException {
final int errorCode = preReboot ? SessionInfo.STAGED_SESSION_VERIFICATION_FAILED
: SessionInfo.STAGED_SESSION_ACTIVATION_FAILED;
if (originalSession.stageDir == null) { if (originalSession.stageDir == null) {
Slog.wtf(TAG, "Attempting to install a staged APK session with no staging dir"); Slog.wtf(TAG, "Attempting to install a staged APK session with no staging dir");
return null; throw new PackageManagerException(errorCode,
"Attempting to install a staged APK session with no staging dir");
} }
List<String> apkFilePaths = findAPKsInDir(originalSession.stageDir); List<String> apkFilePaths = findAPKsInDir(originalSession.stageDir);
if (apkFilePaths.isEmpty()) { if (apkFilePaths.isEmpty()) {
Slog.w(TAG, "Can't find staged APK in " + originalSession.stageDir.getAbsolutePath()); Slog.w(TAG, "Can't find staged APK in " + originalSession.stageDir.getAbsolutePath());
return null; throw new PackageManagerException(errorCode,
"Can't find staged APK in " + originalSession.stageDir.getAbsolutePath());
} }
PackageInstaller.SessionParams params = originalSession.params.copy(); PackageInstaller.SessionParams params = originalSession.params.copy();
@@ -424,20 +430,22 @@ public class StagingManager {
long sizeBytes = pfd.getStatSize(); long sizeBytes = pfd.getStatSize();
if (sizeBytes < 0) { if (sizeBytes < 0) {
Slog.e(TAG, "Unable to get size of: " + apkFilePath); Slog.e(TAG, "Unable to get size of: " + apkFilePath);
return null; throw new PackageManagerException(errorCode,
"Unable to get size of: " + apkFilePath);
} }
apkSession.write(apkFile.getName(), 0, sizeBytes, pfd); apkSession.write(apkFile.getName(), 0, sizeBytes, pfd);
} }
} catch (IOException e) { } catch (IOException e) {
Slog.e(TAG, "Failure to install APK staged session " + originalSession.sessionId, e); Slog.e(TAG, "Failure to install APK staged session " + originalSession.sessionId, e);
return null; throw new PackageManagerException(errorCode, "Failed to write APK session", e);
} }
return apkSession; return apkSession;
} }
private boolean commitApkSession(@NonNull PackageInstallerSession apkSession, private void commitApkSession(@NonNull PackageInstallerSession apkSession,
int originalSessionId, boolean preReboot) { int originalSessionId, boolean preReboot) throws PackageManagerException {
final int errorCode = preReboot ? SessionInfo.STAGED_SESSION_VERIFICATION_FAILED
: SessionInfo.STAGED_SESSION_ACTIVATION_FAILED;
if (!preReboot) { if (!preReboot) {
if ((apkSession.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) { if ((apkSession.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
// If rollback is available for this session, notify the rollback // If rollback is available for this session, notify the rollback
@@ -457,23 +465,24 @@ public class StagingManager {
final Intent result = receiver.getResult(); final Intent result = receiver.getResult();
final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
PackageInstaller.STATUS_FAILURE); PackageInstaller.STATUS_FAILURE);
if (status == PackageInstaller.STATUS_SUCCESS) { if (status != PackageInstaller.STATUS_SUCCESS) {
return true;
} final String errorMessage = result.getStringExtra(
PackageInstaller.EXTRA_STATUS_MESSAGE);
Slog.e(TAG, "Failure to install APK staged session " + originalSessionId + " [" Slog.e(TAG, "Failure to install APK staged session " + originalSessionId + " ["
+ result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]"); + errorMessage + "]");
return false; throw new PackageManagerException(errorCode, errorMessage);
}
} }
private boolean installApksInSession(@NonNull PackageInstallerSession session, private void installApksInSession(@NonNull PackageInstallerSession session,
boolean preReboot) { boolean preReboot) throws PackageManagerException {
final int errorCode = preReboot ? SessionInfo.STAGED_SESSION_VERIFICATION_FAILED
: SessionInfo.STAGED_SESSION_ACTIVATION_FAILED;
if (!session.isMultiPackage() && !isApexSession(session)) { if (!session.isMultiPackage() && !isApexSession(session)) {
// APK single-packaged staged session. Do a regular install. // APK single-packaged staged session. Do a regular install.
PackageInstallerSession apkSession = createAndWriteApkSession(session, preReboot); PackageInstallerSession apkSession = createAndWriteApkSession(session, preReboot);
if (apkSession == null) { commitApkSession(apkSession, session.sessionId, preReboot);
return false;
}
return commitApkSession(apkSession, session.sessionId, preReboot);
} else if (session.isMultiPackage()) { } else if (session.isMultiPackage()) {
// For multi-package staged sessions containing APKs, we identify which child sessions // For multi-package staged sessions containing APKs, we identify which child sessions
// contain an APK, and with those then create a new multi-package group of sessions, // contain an APK, and with those then create a new multi-package group of sessions,
@@ -491,7 +500,7 @@ public class StagingManager {
} }
if (childSessions.isEmpty()) { if (childSessions.isEmpty()) {
// APEX-only multi-package staged session, nothing to do. // APEX-only multi-package staged session, nothing to do.
return true; return;
} }
PackageInstaller.SessionParams params = session.params.copy(); PackageInstaller.SessionParams params = session.params.copy();
params.isStaged = false; params.isStaged = false;
@@ -508,26 +517,24 @@ public class StagingManager {
} catch (IOException e) { } catch (IOException e) {
Slog.e(TAG, "Unable to prepare multi-package session for staged session " Slog.e(TAG, "Unable to prepare multi-package session for staged session "
+ session.sessionId); + session.sessionId);
return false; throw new PackageManagerException(errorCode,
"Unable to prepare multi-package session for staged session");
} }
for (PackageInstallerSession sessionToClone : childSessions) { for (PackageInstallerSession sessionToClone : childSessions) {
PackageInstallerSession apkChildSession = PackageInstallerSession apkChildSession =
createAndWriteApkSession(sessionToClone, preReboot); createAndWriteApkSession(sessionToClone, preReboot);
if (apkChildSession == null) {
return false;
}
try { try {
apkParentSession.addChildSessionId(apkChildSession.sessionId); apkParentSession.addChildSessionId(apkChildSession.sessionId);
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
Slog.e(TAG, "Failed to add a child session for installing the APK files", e); Slog.e(TAG, "Failed to add a child session for installing the APK files", e);
return false; throw new PackageManagerException(errorCode,
"Failed to add a child session " + apkChildSession.sessionId);
} }
} }
return commitApkSession(apkParentSession, session.sessionId, preReboot); commitApkSession(apkParentSession, session.sessionId, preReboot);
} }
// APEX single-package staged session, nothing to do. // APEX single-package staged session, nothing to do.
return true;
} }
void commitSession(@NonNull PackageInstallerSession session) { void commitSession(@NonNull PackageInstallerSession session) {