diff options
| author | 2020-01-16 18:38:17 +0800 | |
|---|---|---|
| committer | 2020-01-20 09:52:40 +0800 | |
| commit | 1fc8b36cf38e2632db68e5d15acd3ff83d1f54aa (patch) | |
| tree | 0c8ebaae9d67f4d34d26af1d4cabb6d62c6bad74 | |
| parent | 805b26acf04867a4e5e7d8e6bc763e089ab73c8e (diff) | |
Fixed NPE in package installer session.
We updated staged sessions to activation failed state when they
aren't in terminal state, and device received ota and reboot. This
happend before the StagingManager resumes the sessions when
the whole set of parent+child sessions have been restored.
A parent session probably cannot find the child session, and a null
exception could happen.
In this change, we do not destroy child sessions before we destroy
the parent session. We only destroy a child session directly if we
are sure that its parent session doesn't exist.
Bug: 147651771
Test: StagedInstallTest
Change-Id: Iac6489a04df35f851aa18a91e1dde2d73928b8ec
| -rw-r--r-- | services/core/java/com/android/server/pm/PackageInstallerService.java | 8 | ||||
| -rw-r--r-- | services/core/java/com/android/server/pm/StagingManager.java | 9 |
2 files changed, 13 insertions, 4 deletions
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 6331dd46c035..10f46fd808c8 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -259,11 +259,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements // atomic install which needs to query sessions, which requires lock on mSessions. boolean isDeviceUpgrading = mPm.isDeviceUpgrading(); for (PackageInstallerSession session : stagedSessionsToRestore) { - if (isDeviceUpgrading && !session.isStagedAndInTerminalState()) { + if (!session.isStagedAndInTerminalState() && session.hasParentSessionId() + && getSession(session.getParentSessionId()) == null) { session.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, - "Build fingerprint has changed"); + "An orphan staged session " + session.sessionId + " is found, " + + "parent " + session.getParentSessionId() + " is missing"); } - mStagingManager.restoreSession(session); + mStagingManager.restoreSession(session, isDeviceUpgrading); } // Broadcasts are not sent while we restore sessions on boot, since no processes would be // ready to listen to them. From now on, we greedily assume that broadcasts requests are diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 7888d1f9612f..74c98f9ef444 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -889,7 +889,7 @@ public class StagingManager { return false; } - void restoreSession(@NonNull PackageInstallerSession session) { + void restoreSession(@NonNull PackageInstallerSession session, boolean isDeviceUpgrading) { PackageInstallerSession sessionToResume = session; synchronized (mStagedSessions) { mStagedSessions.append(session.sessionId, session); @@ -906,6 +906,13 @@ public class StagingManager { } } } + // The preconditions used during pre-reboot verification might have changed when device + // is upgrading. Updated staged sessions to activation failed before we resume the session. + if (isDeviceUpgrading && !sessionToResume.isStagedAndInTerminalState()) { + sessionToResume.setStagedSessionFailed(SessionInfo.STAGED_SESSION_ACTIVATION_FAILED, + "Build fingerprint has changed"); + return; + } checkStateAndResume(sessionToResume); } |