summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Patrick Baumann <patb@google.com> 2020-04-30 19:44:20 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-04-30 19:44:20 +0000
commiteb29d9ac7775180cb6b4deb8233849657053b2b2 (patch)
tree31c00bb389eb5fda756fe277da2bd9e0892ea3b3
parent7334f95129544cee084c3ff04da84a8f61a9425d (diff)
parenta7e1a573d0c8604757023d2151f588bf30d2ec88 (diff)
Merge "Handles child failure on session validate" into rvc-dev
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java71
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) {