Merge "Stop creating extra apk session during pre-reboot verification"

This commit is contained in:
Mohammad Samiul Islam
2020-08-24 09:21:10 +00:00
committed by Android (Google) Code Review
3 changed files with 75 additions and 24 deletions

View File

@@ -134,6 +134,7 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.dex.DexManager;
@@ -1554,12 +1555,28 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
private void onSessionValidationFailure(int error, String detailMessage) {
// Session is sealed but could not be verified, we need to destroy it.
// Session is sealed but could not be validated, we need to destroy it.
destroyInternal();
// Dispatch message to remove session from PackageInstallerService.
dispatchSessionFinished(error, detailMessage, null);
}
private void onSessionVerificationFailure(int error, String detailMessage) {
Slog.e(TAG, "Failed to verify session " + sessionId + " [" + detailMessage + "]");
// Session is sealed and committed but could not be verified, we need to destroy it.
destroyInternal();
if (isStaged()) {
setStagedSessionFailed(
SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, detailMessage);
// TODO(b/136257624): Remove this once all verification logic has been transferred out
// of StagingManager.
mStagingManager.notifyVerificationComplete(sessionId);
} else {
// Dispatch message to remove session from PackageInstallerService.
dispatchSessionFinished(error, detailMessage, null);
}
}
private void onStorageUnhealthy() {
final String packageName = getPackageName();
if (TextUtils.isEmpty(packageName)) {
@@ -1680,7 +1697,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
if (params.isStaged) {
mStagingManager.commitSession(this);
destroyInternal();
// 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(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
return;
}
@@ -1691,14 +1709,30 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
"APEX packages can only be installed using staged sessions.", null);
return;
}
verify();
}
/**
* Resumes verification process for non-final committed staged session.
*
* Useful if a device gets rebooted before verification is complete and we need to restart the
* verification.
*/
void verifyStagedSession() {
assertCallerIsOwnerOrRootOrSystemLocked();
Preconditions.checkArgument(isCommitted());
Preconditions.checkArgument(isStaged());
Preconditions.checkArgument(!mStagedSessionApplied && !mStagedSessionFailed);
verify();
}
private void verify() {
try {
verifyNonStaged();
} catch (PackageManagerException e) {
final String completeMsg = ExceptionUtils.getCompleteMessage(e);
Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
destroyInternal();
dispatchSessionFinished(e.error, completeMsg, null);
onSessionVerificationFailure(e.error, completeMsg);
}
}
@@ -1846,7 +1880,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
@GuardedBy("mLock")
private PackageManagerService.VerificationParams makeVerificationParamsLocked()
throws PackageManagerException {
if (!params.isMultiPackage) {
// TODO(b/136257624): Some logic in this if block probably belongs in
// makeInstallParams().
if (!params.isMultiPackage && !isApexInstallation()) {
Objects.requireNonNull(mPackageName);
Objects.requireNonNull(mSigningDetails);
Objects.requireNonNull(mResolvedBaseFile);
@@ -1923,8 +1959,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
if (returnCode == PackageManager.INSTALL_SUCCEEDED) {
onVerificationComplete();
} else {
destroyInternal();
dispatchSessionFinished(returnCode, msg, extras);
onSessionVerificationFailure(returnCode, msg);
}
}
};
@@ -1946,9 +1981,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
private void onVerificationComplete() {
if ((params.installFlags & PackageManager.INSTALL_DRY_RUN) != 0) {
destroyInternal();
dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Dry run", new Bundle());
// Staged sessions will be installed later during boot
if (isStaged()) {
// TODO(b/136257624): Remove this once all verification logic has been transferred out
// of StagingManager.
mStagingManager.notifyPreRebootVerification_Apk_Complete(sessionId);
// TODO(b/136257624): We also need to destroy internals for verified staged session,
// otherwise file descriptors are never closed for verified staged session until reboot
return;
}

View File

@@ -15201,6 +15201,13 @@ public class PackageManagerService extends IPackageManager.Stub
}
public void handleStartCopy() {
if ((installFlags & PackageManager.INSTALL_APEX) != 0) {
// Apex packages get verified in StagingManager currently.
// TODO(b/136257624): Move apex verification logic out of StagingManager
mRet = INSTALL_SUCCEEDED;
return;
}
PackageInfoLite pkgLite = PackageManagerServiceUtils.getMinimalPackageInfo(mContext,
origin.resolvedPath, installFlags, packageAbiOverride);

View File

@@ -1299,6 +1299,20 @@ public class StagingManager {
return session;
}
// TODO(b/136257624): Temporary API to let PMS communicate with StagingManager. When all
// verification logic is extraced out of StagingManager into PMS, we can remove
// this.
void notifyVerificationComplete(int sessionId) {
mPreRebootVerificationHandler.onPreRebootVerificationComplete(sessionId);
}
// TODO(b/136257624): Temporary API to let PMS communicate with StagingManager. When all
// verification logic is extraced out of StagingManager into PMS, we can remove
// this.
void notifyPreRebootVerification_Apk_Complete(int sessionId) {
mPreRebootVerificationHandler.notifyPreRebootVerification_Apk_Complete(sessionId);
}
private final class PreRebootVerificationHandler extends Handler {
// Hold session ids before handler gets ready to do the verification.
private IntArray mPendingSessionIds;
@@ -1500,25 +1514,16 @@ public class StagingManager {
}
/**
* Pre-reboot verification state for apk files:
* <p><ul>
* <li>performs a dry-run install of apk</li>
* </ul></p>
* Pre-reboot verification state for apk files. Session is sent to
* {@link PackageManagerService} for verification and it notifies back the result via
* {@link #notifyPreRebootVerification_Apk_Complete(int)}
*/
private void handlePreRebootVerification_Apk(@NonNull PackageInstallerSession session) {
if (!sessionContainsApk(session)) {
notifyPreRebootVerification_Apk_Complete(session.sessionId);
return;
}
try {
Slog.d(TAG, "Running a pre-reboot verification for APKs in session "
+ session.sessionId + " by performing a dry-run install");
// verifyApksInSession will notify the handler when APK verification is complete
verifyApksInSession(session);
} catch (PackageManagerException e) {
onPreRebootVerificationFailure(session, e.error, e.getMessage());
}
session.verifyStagedSession();
}
private void verifyApksInSession(PackageInstallerSession session)