From 769f815c68a13387a549d54f57176207b76337eb Mon Sep 17 00:00:00 2001 From: Alex Buynytskyy Date: Thu, 23 Jan 2020 16:58:45 +0000 Subject: [PATCH] On reboot session handling. - re-seal regular sessions, - re-seal+validate APEX sessions. Previously we were validating them as well. This is unnecessary as validation will happen on commit/transfer calls later. This was introduced in 43f1af9dd9ce7873d7ede94cc72fc59c7c71283d when we were using mSealed flag for both sealing and validation. It's not the case anymore and we can safely deffer validation to commit/transfer. Test: atest PackageManagerShellCommandTest SplitTests StagedRollbackTest CtsAtomicInstallTestCases PackageInstallerSessionTest InstallSessionTransferTest Bug: b/136132412 Change-Id: I1ccb29ad41e25561f4f54ea51da3b9a725dd5647 --- .../server/pm/PackageInstallerService.java | 4 +- .../server/pm/PackageInstallerSession.java | 39 +++++++++++++------ 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 10f46fd808c83..c17ad11196315 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -402,10 +402,10 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } finally { IoUtils.closeQuietly(fis); } - // After all of the sessions were loaded, they are ready to be sealed and validated + // After reboot housekeeping. for (int i = 0; i < mSessions.size(); ++i) { PackageInstallerSession session = mSessions.valueAt(i); - session.sealAndValidateIfNecessary(); + session.onAfterSessionRead(); } } diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index ef2873358cd45..c3102f70a8100 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -372,6 +372,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // TODO(b/146080380): merge file list with Callback installation. private IncrementalFileStorages mIncrementalFileStorages; + private static final String[] EMPTY_STRING_ARRAY = new String[]{}; + private static final FileFilter sAddedFilter = new FileFilter() { @Override public boolean accept(File file) { @@ -713,7 +715,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private String[] getNamesLocked() { if (!isDataLoaderInstallation()) { - return stageDir.list(); + String[] result = stageDir.list(); + if (result == null) { + result = EMPTY_STRING_ARRAY; + } + return result; } return mFiles.stream().map(fileInfo -> fileInfo.name).toArray(String[]::new); } @@ -1339,7 +1345,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { prepareDataLoader(); - if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) { + if (isApexInstallation()) { validateApexInstallLocked(); } else { validateApkInstallLocked(pkgInfo); @@ -1370,15 +1376,15 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } /** - * If session should be sealed, then it's sealed to prevent further modification - * and then it's validated. + * If session should be sealed, then it's sealed to prevent further modification. + * If the session can't be sealed then it's destroyed. * - * If the session was sealed but something went wrong then it's destroyed. + * Additionally for staged APEX sessions read+validate the package and populate req'd fields. * *

This is meant to be called after all of the sessions are loaded and added to * PackageInstallerService */ - void sealAndValidateIfNecessary() { + void onAfterSessionRead() { synchronized (mLock) { if (!mShouldBeSealed || isStagedAndInTerminalState()) { return; @@ -1387,9 +1393,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { List childSessions = getChildSessions(); synchronized (mLock) { try { - sealAndValidateLocked(childSessions); - } catch (StreamingException e) { - Slog.e(TAG, "Streaming failed", e); + sealLocked(childSessions); + + if (isApexInstallation()) { + // APEX installations rely on certain fields to be populated after reboot. + // E.g. mPackageName. + validateApexInstallLocked(); + } } catch (PackageManagerException e) { Slog.e(TAG, "Package not valid", e); } @@ -1465,7 +1475,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { return; } - if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) { + if (isApexInstallation()) { destroyInternal(); dispatchSessionFinished(PackageManager.INSTALL_FAILED_INTERNAL_ERROR, "APEX packages can only be installed using staged sessions.", null); @@ -1549,7 +1559,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } final IPackageInstallObserver2 localObserver; - if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) { + if (isApexInstallation()) { localObserver = null; } else { if (!params.isMultiPackage) { @@ -1683,6 +1693,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { (params.installFlags & PackageManager.DONT_KILL_APP) != 0; } + /** + * Returns true if the session is installing an APEX package. + */ + private boolean isApexInstallation() { + return (params.installFlags & PackageManager.INSTALL_APEX) != 0; + } + /** * Validate apex install. *