Iterate over parent sessions (1/n)

Use #sessionContains(filter) to check if there is overlapping.

This allows us to store only parent sessions in #mStagedSessions and move
the call to #createSession from PackageInstallerService into StagingManager
in the future.

Bug: 168268518
Test: atest StagedInstallTest
Change-Id: I1d8f71149cd9957f45b6bcaee3e75dd68c8a45d4
This commit is contained in:
JW Wang
2020-09-11 14:29:56 +08:00
parent e1505c7959
commit 863fe45224
2 changed files with 11 additions and 24 deletions

View File

@@ -2250,7 +2250,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
return (params.installFlags & PackageManager.INSTALL_APEX) != 0;
}
private boolean sessionContains(Predicate<PackageInstallerSession> filter) {
boolean sessionContains(Predicate<PackageInstallerSession> filter) {
if (!isMultiPackage()) {
return filter.test(this);
}

View File

@@ -863,7 +863,9 @@ public class StagingManager {
// We cannot say a parent session overlaps until we process its children
return;
}
if (session.getPackageName() == null) {
String packageName = session.getPackageName();
if (packageName == null) {
throw new PackageManagerException(PackageManager.INSTALL_FAILED_INVALID_APK,
"Cannot stage session " + session.sessionId + " with package name null");
}
@@ -876,40 +878,26 @@ public class StagingManager {
synchronized (mStagedSessions) {
for (int i = 0; i < mStagedSessions.size(); i++) {
final PackageInstallerSession stagedSession = mStagedSessions.valueAt(i);
if (!stagedSession.isCommitted() || stagedSession.isStagedAndInTerminalState()
if (stagedSession.hasParentSessionId() || !stagedSession.isCommitted()
|| stagedSession.isStagedAndInTerminalState()
|| stagedSession.isDestroyed()) {
continue;
}
if (stagedSession.isMultiPackage()) {
// This active parent staged session is useless as it doesn't have a package
// name and the session we are checking is not a parent session either.
continue;
}
// Check if stagedSession has an active parent session or not
if (stagedSession.hasParentSessionId()) {
final int parentId = stagedSession.getParentSessionId();
final PackageInstallerSession parentSession = mStagedSessions.get(parentId);
if (parentSession == null || parentSession.isStagedAndInTerminalState()
|| parentSession.isDestroyed()) {
// Parent session has been abandoned or terminated already
continue;
}
}
// From here on, stagedSession is a non-parent active staged session
// From here on, stagedSession is a parent active staged session
// Check if session is one of the active sessions
if (session.sessionId == stagedSession.sessionId) {
if (getSessionIdForParentOrSelf(session) == stagedSession.sessionId) {
Slog.w(TAG, "Session " + session.sessionId + " is already staged");
continue;
}
// New session cannot have same package name as one of the active sessions
if (session.getPackageName().equals(stagedSession.getPackageName())) {
if (stagedSession.sessionContains(s -> s.getPackageName().equals(packageName))) {
if (isRollback) {
// If the new session is a rollback, then it gets priority. The existing
// session is failed to unblock rollback.
final PackageInstallerSession root = getParentSessionOrSelf(stagedSession);
final PackageInstallerSession root = stagedSession;
if (!ensureActiveApexSessionIsAborted(root)) {
Slog.e(TAG, "Failed to abort apex session " + root.sessionId);
// Safe to ignore active apex session abort failure since session
@@ -933,8 +921,7 @@ public class StagingManager {
// Staging multiple root sessions is not allowed if device doesn't support
// checkpoint. If session and stagedSession do not have common ancestor, they are
// from two different root sessions.
if (!supportsCheckpoint && getSessionIdForParentOrSelf(session)
!= getSessionIdForParentOrSelf(stagedSession)) {
if (!supportsCheckpoint) {
throw new PackageManagerException(
PackageManager.INSTALL_FAILED_OTHER_STAGED_SESSION_IN_PROGRESS,
"Cannot stage multiple sessions without checkpoint support", null);