From 6473c8ea195367ed950a969279929f4a4519dbf7 Mon Sep 17 00:00:00 2001 From: Samiul Islam Date: Tue, 1 Jun 2021 09:44:57 +0100 Subject: [PATCH] Update the session object with the error msg from ApexSessionInfo Now that apexd returns an error message with details about why APEX activation has failed, we can append it to session object's error message. Bug: 178192690 Test: atest StagedInstallInternalTest#testApexActivationFailureIsCapturedInSession Change-Id: Id2d1df7f86ca85b044cfa15990eae548a176882b --- .../com/android/server/pm/StagingManager.java | 3 +-- .../android/server/pm/StagingManagerTest.java | 5 +++-- tests/StagedInstallTest/Android.bp | 1 + .../StagedInstallInternalTest.java | 20 +++++++++++++++++ .../host/StagedInstallInternalTest.java | 22 +++++++++++++++++++ 5 files changed, 47 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 4a68b7606c601..c842ff1b11a58 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -955,8 +955,7 @@ public class StagingManager { continue; } else if (isApexSessionFailed(apexSession)) { hasFailedApexSession = true; - String errorMsg = "APEX activation failed. Check logcat messages from apexd " - + "for more information."; + String errorMsg = "APEX activation failed. " + apexSession.errorMessage; if (!TextUtils.isEmpty(apexSession.crashingNativeProcess)) { prepareForLoggingApexdRevert(session, apexSession.crashingNativeProcess); errorMsg = "Session reverted due to crashing native process: " diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java index 7d628be571a97..68570ffc6fcef 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java @@ -286,6 +286,7 @@ public class StagingManagerTest { ApexSessionInfo activationFailed = new ApexSessionInfo(); activationFailed.sessionId = 1543; activationFailed.isActivationFailed = true; + activationFailed.errorMessage = "Failed for test"; ApexSessionInfo staged = new ApexSessionInfo(); staged.sessionId = 101; @@ -309,8 +310,8 @@ public class StagingManagerTest { assertThat(apexSession1.getErrorCode()) .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED); - assertThat(apexSession1.getErrorMessage()).isEqualTo("APEX activation failed. Check logcat " - + "messages from apexd for more information."); + assertThat(apexSession1.getErrorMessage()).isEqualTo("APEX activation failed. " + + "Failed for test"); assertThat(apexSession2.getErrorCode()) .isEqualTo(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED); diff --git a/tests/StagedInstallTest/Android.bp b/tests/StagedInstallTest/Android.bp index c679d04876297..c563e06ab5287 100644 --- a/tests/StagedInstallTest/Android.bp +++ b/tests/StagedInstallTest/Android.bp @@ -52,6 +52,7 @@ java_test_host { data: [ ":com.android.apex.apkrollback.test_v1", ":com.android.apex.cts.shim.v2_prebuilt", + ":StagedInstallTestApexV2_WrongSha", ":TestAppAv1", ], test_suites: ["general-tests"], diff --git a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java index e633c87d7fbbb..6a62304f9af7b 100644 --- a/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/app/src/com/android/tests/stagedinstallinternal/StagedInstallInternalTest.java @@ -179,6 +179,26 @@ public class StagedInstallInternalTest { assertThat(info.isStagedSessionFailed()).isTrue(); } + @Test + public void testApexActivationFailureIsCapturedInSession_Commit() throws Exception { + int sessionId = Install.single(TestApp.Apex1).setStaged().commit(); + assertSessionReady(sessionId); + storeSessionId(sessionId); + } + + @Test + public void testApexActivationFailureIsCapturedInSession_Verify() throws Exception { + int sessionId = retrieveLastSessionId(); + assertSessionFailedWithMessage(sessionId, "has unexpected SHA512 hash"); + } + + private static void assertSessionFailedWithMessage(int sessionId, String msg) { + assertSessionState(sessionId, (session) -> { + assertThat(session.isStagedSessionFailed()).isTrue(); + assertThat(session.getStagedSessionErrorMessage()).contains(msg); + }); + } + private static void assertSessionReady(int sessionId) { assertSessionState(sessionId, (session) -> assertThat(session.isStagedSessionReady()).isTrue()); diff --git a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java index ccd63f94de548..5d7fdd183dec9 100644 --- a/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java +++ b/tests/StagedInstallTest/src/com/android/tests/stagedinstallinternal/host/StagedInstallInternalTest.java @@ -56,6 +56,7 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { @Rule public AbandonSessionsRule mHostTestRule = new AbandonSessionsRule(this); private static final String SHIM_V2 = "com.android.apex.cts.shim.v2.apex"; + private static final String APEX_WRONG_SHA = "com.android.apex.cts.shim.v2_wrong_sha.apex"; private static final String APK_A = "TestAppAv1.apk"; private static final String APK_IN_APEX_TESTAPEX_NAME = "com.android.apex.apkrollback.test"; @@ -322,6 +323,27 @@ public class StagedInstallInternalTest extends BaseHostJUnit4Test { runPhase("testFailStagedSessionIfStagingDirectoryDeleted_Verify"); } + @Test + public void testApexActivationFailureIsCapturedInSession() throws Exception { + // We initiate staging a normal apex update which passes pre-reboot verification. + // Then we replace the valid apex waiting in /data/app-staging with something + // that cannot be activated and reboot. The apex should fail to activate, which + // is what we want for this test. + runPhase("testApexActivationFailureIsCapturedInSession_Commit"); + final String sessionId = getDevice().executeShellCommand( + "pm get-stagedsessions --only-ready --only-parent --only-sessionid").trim(); + assertThat(sessionId).isNotEmpty(); + // Now replace the valid staged apex with something invalid + getDevice().enableAdbRoot(); + getDevice().executeShellCommand("rm /data/app-staging/session_" + sessionId + "/*"); + final File invalidApexFile = mHostUtils.getTestFile(APEX_WRONG_SHA); + getDevice().pushFile(invalidApexFile, + "/data/app-staging/session_" + sessionId + "/base.apex"); + getDevice().reboot(); + + runPhase("testApexActivationFailureIsCapturedInSession_Verify"); + } + private List getStagingDirectories() throws DeviceNotAvailableException { String baseDir = "/data/app-staging"; try {