summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/pm/ApexManager.java19
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java128
2 files changed, 73 insertions, 74 deletions
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 249b6801758b..07527c2a15d8 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -270,11 +270,12 @@ public abstract class ApexManager {
abstract boolean revertActiveSessions();
/**
- * Abandons the staged session with the given sessionId.
+ * Abandons the staged session with the given sessionId. Client should handle {@code false}
+ * return value carefully as failure here can leave device in inconsistent state.
*
- * @return {@code true} upon success, {@code false} if any remote exception occurs
+ * @return {@code true} upon success, {@code false} if any exception occurs
*/
- abstract boolean abortStagedSession(int sessionId) throws PackageManagerException;
+ abstract boolean abortStagedSession(int sessionId);
/**
* Uninstalls given {@code apexPackage}.
@@ -753,17 +754,13 @@ public abstract class ApexManager {
}
@Override
- boolean abortStagedSession(int sessionId) throws PackageManagerException {
+ boolean abortStagedSession(int sessionId) {
try {
waitForApexService().abortStagedSession(sessionId);
return true;
- } catch (RemoteException re) {
- Slog.e(TAG, "Unable to contact apexservice", re);
- return false;
} catch (Exception e) {
- throw new PackageManagerException(
- PackageInstaller.SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
- "Failed to abort staged session : " + e.getMessage());
+ Slog.e(TAG, e.getMessage(), e);
+ return false;
}
}
@@ -1122,7 +1119,7 @@ public abstract class ApexManager {
}
@Override
- boolean abortStagedSession(int sessionId) throws PackageManagerException {
+ boolean abortStagedSession(int sessionId) {
throw new UnsupportedOperationException();
}
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 616e5d13f990..12591b48ad52 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -322,9 +322,6 @@ public class StagingManager {
}
final long activeVersion = activePackage.applicationInfo.longVersionCode;
if (activeVersion != session.params.requiredInstalledVersionCode) {
- if (!mApexManager.abortStagedSession(session.sessionId)) {
- Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
- }
throw new PackageManagerException(
SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
"Installed version of APEX package " + activePackage.packageName
@@ -338,14 +335,11 @@ public class StagingManager {
throws PackageManagerException {
final long activeVersion = activePackage.applicationInfo.longVersionCode;
final long newVersionCode = newPackage.applicationInfo.longVersionCode;
- boolean isAppDebuggable = (activePackage.applicationInfo.flags
+ final boolean isAppDebuggable = (activePackage.applicationInfo.flags
& ApplicationInfo.FLAG_DEBUGGABLE) != 0;
final boolean allowsDowngrade = PackageManagerServiceUtils.isDowngradePermitted(
session.params.installFlags, isAppDebuggable);
if (activeVersion > newVersionCode && !allowsDowngrade) {
- if (!mApexManager.abortStagedSession(session.sessionId)) {
- Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
- }
throw new PackageManagerException(
SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
"Downgrade of APEX package " + newPackage.packageName
@@ -834,37 +828,6 @@ public class StagingManager {
return null;
}
- private void verifyApksInSession(PackageInstallerSession session)
- throws PackageManagerException {
-
- final PackageInstallerSession apksToVerify = extractApksInSession(
- session, /* preReboot */ true);
- if (apksToVerify == null) {
- return;
- }
-
- final LocalIntentReceiverAsync receiver = new LocalIntentReceiverAsync(
- (Intent result) -> {
- int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
- PackageInstaller.STATUS_FAILURE);
- if (status != PackageInstaller.STATUS_SUCCESS) {
- final String errorMessage = result.getStringExtra(
- PackageInstaller.EXTRA_STATUS_MESSAGE);
- Slog.e(TAG, "Failure to verify APK staged session "
- + session.sessionId + " [" + errorMessage + "]");
- session.setStagedSessionFailed(
- SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, errorMessage);
- mPreRebootVerificationHandler.onPreRebootVerificationComplete(
- session.sessionId);
- return;
- }
- mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete(
- session.sessionId);
- });
-
- apksToVerify.commit(receiver.getIntentSender(), false);
- }
-
private void installApksInSession(@NonNull PackageInstallerSession session)
throws PackageManagerException {
@@ -1041,23 +1004,11 @@ public class StagingManager {
// A session could be marked ready once its pre-reboot verification ends
if (session.isStagedSessionReady()) {
- if (sessionContainsApex(session)) {
- try {
- ApexSessionInfo apexSession =
- mApexManager.getStagedSessionInfo(session.sessionId);
- if (apexSession == null || isApexSessionFinalized(apexSession)) {
- Slog.w(TAG,
- "Cannot abort session " + session.sessionId
- + " because it is not active.");
- } else {
- mApexManager.abortStagedSession(session.sessionId);
- }
- } catch (Exception e) {
- // Failed to contact apexd service. The apex might still be staged. We can still
- // safely cleanup the staged session since pre-reboot verification is complete.
- // Also, cleaning up the stageDir prevents the apex from being activated.
- Slog.w(TAG, "Could not contact apexd to abort staged session " + sessionId);
- }
+ if (!ensureActiveApexSessionIsAborted(session)) {
+ // Failed to ensure apex session is aborted, so it can still be staged. We can still
+ // safely cleanup the staged session since pre-reboot verification is complete.
+ // Also, cleaning up the stageDir prevents the apex from being activated.
+ Slog.e(TAG, "Failed to abort apex session " + session.sessionId);
}
}
@@ -1067,6 +1018,22 @@ public class StagingManager {
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;
+ }
+ return mApexManager.abortStagedSession(session.sessionId);
+ }
+
private boolean isApexSessionFinalized(ApexSessionInfo session) {
/* checking if the session is in a final state, i.e., not active anymore */
return session.isUnknown || session.isActivationFailed || session.isSuccess
@@ -1347,6 +1314,17 @@ public class StagingManager {
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
private void onPreRebootVerificationComplete(int sessionId) {
// Remove it from mVerificationRunning so that verification is considered complete
@@ -1431,8 +1409,7 @@ public class StagingManager {
validateApexSignature(apexPackages.get(i));
}
} catch (PackageManagerException e) {
- session.setStagedSessionFailed(e.error, e.getMessage());
- onPreRebootVerificationComplete(session.sessionId);
+ onPreRebootVerificationFailure(session, e.error, e.getMessage());
return;
}
@@ -1459,16 +1436,42 @@ public class StagingManager {
try {
Slog.d(TAG, "Running a pre-reboot verification for APKs in session "
+ session.sessionId + " by performing a dry-run install");
-
// verifyApksInSession will notify the handler when APK verification is complete
verifyApksInSession(session);
- // TODO(b/118865310): abort the session on apexd.
} catch (PackageManagerException e) {
- session.setStagedSessionFailed(e.error, e.getMessage());
- onPreRebootVerificationComplete(session.sessionId);
+ onPreRebootVerificationFailure(session, e.error, e.getMessage());
}
}
+ private void verifyApksInSession(PackageInstallerSession session)
+ throws PackageManagerException {
+
+ final PackageInstallerSession apksToVerify = extractApksInSession(
+ session, /* preReboot */ true);
+ if (apksToVerify == null) {
+ return;
+ }
+
+ final LocalIntentReceiverAsync receiver = new LocalIntentReceiverAsync(
+ (Intent result) -> {
+ final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
+ PackageInstaller.STATUS_FAILURE);
+ if (status != PackageInstaller.STATUS_SUCCESS) {
+ final String errorMessage = result.getStringExtra(
+ PackageInstaller.EXTRA_STATUS_MESSAGE);
+ Slog.e(TAG, "Failure to verify APK staged session "
+ + session.sessionId + " [" + errorMessage + "]");
+ onPreRebootVerificationFailure(session,
+ SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, errorMessage);
+ return;
+ }
+ mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete(
+ session.sessionId);
+ });
+
+ apksToVerify.commit(receiver.getIntentSender(), false);
+ }
+
/**
* Pre-reboot verification state for wrapping up:
* <p><ul>
@@ -1486,9 +1489,8 @@ public class StagingManager {
} catch (Exception e) {
// Failed to get hold of StorageManager
Slog.e(TAG, "Failed to get hold of StorageManager", e);
- session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_UNKNOWN,
+ onPreRebootVerificationFailure(session, SessionInfo.STAGED_SESSION_UNKNOWN,
"Failed to get hold of StorageManager");
- onPreRebootVerificationComplete(session.sessionId);
return;
}