diff options
| author | 2020-04-30 19:44:20 +0000 | |
|---|---|---|
| committer | 2020-04-30 19:44:20 +0000 | |
| commit | eb29d9ac7775180cb6b4deb8233849657053b2b2 (patch) | |
| tree | 31c00bb389eb5fda756fe277da2bd9e0892ea3b3 | |
| parent | 7334f95129544cee084c3ff04da84a8f61a9425d (diff) | |
| parent | a7e1a573d0c8604757023d2151f588bf30d2ec88 (diff) | |
Merge "Handles child failure on session validate" into rvc-dev
| -rw-r--r-- | services/core/java/com/android/server/pm/PackageInstallerSession.java | 71 |
1 files changed, 52 insertions, 19 deletions
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 9c0ac1884bd5..33a11166d832 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -1122,21 +1122,52 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } private void handleStreamValidateAndCommit() { - boolean success = streamValidateAndCommit(); + PackageManagerException unrecoverableFailure = null; + // This will track whether the session and any children were validated and are ready to + // progress to the next phase of install + boolean allSessionsReady = false; + try { + allSessionsReady = streamValidateAndCommit(); + } catch (PackageManagerException e) { + unrecoverableFailure = e; + } if (isMultiPackage()) { - for (int i = mChildSessionIds.size() - 1; i >= 0; --i) { + int childCount = mChildSessionIds.size(); + + // This will contain all child sessions that do not encounter an unrecoverable failure + ArrayList<PackageInstallerSession> nonFailingSessions = new ArrayList<>(childCount); + + for (int i = childCount - 1; i >= 0; --i) { final int childSessionId = mChildSessionIds.keyAt(i); // commit all children, regardless if any of them fail; we'll throw/return // as appropriate once all children have been processed - if (!mSessionProvider.getSession(childSessionId) - .streamValidateAndCommit()) { - success = false; + try { + PackageInstallerSession session = mSessionProvider.getSession(childSessionId); + if (!session.streamValidateAndCommit()) { + allSessionsReady = false; + } + nonFailingSessions.add(session); + } catch (PackageManagerException e) { + allSessionsReady = false; + if (unrecoverableFailure == null) { + unrecoverableFailure = e; + } + } + } + // If we encountered any unrecoverable failures, destroy all + // other impacted sessions besides the parent; that will be cleaned up by the + // ChildStatusIntentReceiver. + if (unrecoverableFailure != null) { + // fail other child sessions that did not already fail + for (int i = nonFailingSessions.size() - 1; i >= 0; --i) { + PackageInstallerSession session = nonFailingSessions.get(i); + session.onSessionVerificationFailure(unrecoverableFailure); } } } - if (!success) { + if (!allSessionsReady) { return; } @@ -1216,14 +1247,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mStatusReceiver.sendIntent(mContext, 0, intent, null, null); } catch (IntentSender.SendIntentException ignore) { } - } else { + } else { // failure, let's forward and clean up this session. intent.putExtra(PackageInstaller.EXTRA_SESSION_ID, PackageInstallerSession.this.sessionId); mChildSessionsRemaining.clear(); // we're done. Don't send any more. - try { - mStatusReceiver.sendIntent(mContext, 0, intent, null, null); - } catch (IntentSender.SendIntentException ignore) { - } + onSessionVerificationFailure(status, + intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE)); } }); } @@ -1329,7 +1358,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return true; } - private boolean streamValidateAndCommit() { + /** + * Returns true if the session is successfully validated and committed. Returns false if the + * dataloader could not be prepared. This can be called multiple times so long as no + * exception is thrown. + * @throws PackageManagerException on an unrecoverable error. + */ + private boolean streamValidateAndCommit() throws PackageManagerException { synchronized (mLock) { if (mCommitted) { return true; @@ -1349,7 +1384,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mCommitted = true; } - return true; } @@ -1449,10 +1483,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { * Prepare DataLoader and stream content for DataLoader sessions. * Validate the contents of all session. * - * @return false if validation failed. + * @return false if the data loader could not be prepared. + * @throws PackageManagerException when an unrecoverable exception is encountered */ @GuardedBy("mLock") - private boolean streamAndValidateLocked() { + private boolean streamAndValidateLocked() throws PackageManagerException { try { // Read transfers from the original owner stay open, but as the session's data cannot // be modified anymore, there is no leak of information. For staged sessions, further @@ -1472,16 +1507,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (params.isStaged) { mStagingManager.checkNonOverlappingWithStagedSessions(this); } - return true; } catch (PackageManagerException e) { - onSessionVerificationFailure(e); + throw onSessionVerificationFailure(e); } catch (Throwable e) { // Convert all exceptions into package manager exceptions as only those are handled // in the code above. - onSessionVerificationFailure(new PackageManagerException(e)); + throw onSessionVerificationFailure(new PackageManagerException(e)); } - return false; } private PackageManagerException onSessionVerificationFailure(PackageManagerException e) { |