Merge "Handles child failure on session validate" into rvc-dev am: eb29d9ac77

Change-Id: I7f41b4d16a423c100fdc3d184d79f188ffdd09bc
This commit is contained in:
Patrick Baumann
2020-04-30 19:53:23 +00:00
committed by Automerger Merge Worker

View File

@@ -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) {