summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Rhed Jao <rhedjao@google.com> 2020-01-16 18:38:17 +0800
committer Rhed Jao <rhedjao@google.com> 2020-01-20 09:52:40 +0800
commit1fc8b36cf38e2632db68e5d15acd3ff83d1f54aa (patch)
tree0c8ebaae9d67f4d34d26af1d4cabb6d62c6bad74
parent805b26acf04867a4e5e7d8e6bc763e089ab73c8e (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.java8
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java9
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);
}