Call dispatchSessionFinished() on a staged session when finished (3/n)

* Improve consistency between staged and non-staged sessions.
* It is up to the PackageInstallerService policy to decide how
  to retain finished sessions for debugging purposes.
* onSessionFinished() now keeps finished staged sessions if they are
  not explicitly abandoned by the user (isDestroyed() is true)
  to preserve the original behavior.

Bug: 210359798
Test: atest StagingManagerTest \
            PackageInstallerSessionTest \
            CtsStagedInstallHostTestCases

Change-Id: I87f9c2b562206e20d96f212865df2320d6e3c627
This commit is contained in:
JW Wang
2021-11-29 14:22:27 +08:00
parent af8ff1c9a3
commit 95f8662bd5
2 changed files with 30 additions and 21 deletions

View File

@@ -513,19 +513,25 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
if (!valid) {
Slog.w(TAG, "Remove old session: " + session.sessionId);
// Remove expired sessions as well as child sessions if any
mSessions.remove(session.sessionId);
// Since this is early during boot we don't send
// any observer events about the session, but we
// keep details around for dumpsys.
addHistoricalSessionLocked(session);
for (PackageInstallerSession child : session.getChildSessions()) {
mSessions.remove(child.sessionId);
addHistoricalSessionLocked(child);
}
removeActiveSession(session);
}
}
}
/**
* Moves a session (including the child sessions) from mSessions to mHistoricalSessions.
* This should only be called on a root session.
*/
@GuardedBy("mSessions")
private void removeActiveSession(PackageInstallerSession session) {
mSessions.remove(session.sessionId);
addHistoricalSessionLocked(session);
for (PackageInstallerSession child : session.getChildSessions()) {
mSessions.remove(child.sessionId);
addHistoricalSessionLocked(child);
}
}
@GuardedBy("mSessions")
private void addHistoricalSessionLocked(PackageInstallerSession session) {
CharArrayWriter writer = new CharArrayWriter();
@@ -1654,10 +1660,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
mStagingManager.abortSession(session.mStagedSession);
}
synchronized (mSessions) {
if (!session.isStaged() || !success) {
mSessions.remove(session.sessionId);
// Child sessions will be removed along with its parent as a whole
if (!session.hasParentSessionId()
&& (!session.isStaged() || session.isDestroyed())) {
removeActiveSession(session);
}
addHistoricalSessionLocked(session);
final File appIconFile = buildAppIconFile(session.sessionId);
if (appIconFile.exists()) {

View File

@@ -27,6 +27,7 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
import static android.content.pm.PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SPLIT;
import static android.content.pm.PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
import static android.content.pm.PackageManager.INSTALL_STAGED;
import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
@@ -2097,10 +2098,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
} else {
// Session is sealed and committed but could not be verified, we need to destroy it.
destroy();
// Dispatch message to remove session from PackageInstallerService.
dispatchSessionFinished(error, msg, null);
maybeFinishChildSessions(error, msg);
}
// Dispatch message to remove session from PackageInstallerService.
dispatchSessionFinished(error, msg, null);
maybeFinishChildSessions(error, msg);
}
private void onSessionInstallationFailure(int error, String detailedMessage) {
@@ -2301,7 +2302,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (params.isStaged) {
// TODO(b/136257624): CTS test fails if we don't send session finished broadcast, even
// though ideally, we just need to send session committed broadcast.
dispatchSessionFinished(INSTALL_SUCCEEDED, "Session staged", null);
sendUpdateToRemoteStatusReceiver(INSTALL_SUCCEEDED, "Session staged", null);
mStagedSession.verifySession();
} else {
@@ -2549,6 +2550,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
mStagedSession.notifyEndPreRebootVerification();
if (error == SessionInfo.SESSION_NO_ERROR) {
mStagingManager.commitSession(mStagedSession);
} else {
dispatchSessionFinished(INSTALL_FAILED_VERIFICATION_FAILURE, msg, null);
maybeFinishChildSessions(INSTALL_FAILED_VERIFICATION_FAILURE, msg);
}
});
return;
@@ -2578,7 +2582,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
// Do not try to install staged apex session. Parent session will have at least one apk
// session.
if (!isMultiPackage() && isApexSession() && params.isStaged) {
sendUpdateToRemoteStatusReceiver(INSTALL_SUCCEEDED,
dispatchSessionFinished(INSTALL_SUCCEEDED,
"Apex package should have been installed by apexd", null);
return null;
}
@@ -2592,14 +2596,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@Override
public void onPackageInstalled(String basePackageName, int returnCode, String msg,
Bundle extras) {
if (isStaged()) {
sendUpdateToRemoteStatusReceiver(returnCode, msg, extras);
} else {
if (!isStaged()) {
// We've reached point of no return; call into PMS to install the stage.
// Regardless of success or failure we always destroy session.
destroyInternal();
dispatchSessionFinished(returnCode, msg, extras);
}
dispatchSessionFinished(returnCode, msg, extras);
}
};