diff options
4 files changed, 44 insertions, 26 deletions
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java index 8904ee61e2e3..a236300a56cf 100644 --- a/core/java/android/os/Environment.java +++ b/core/java/android/os/Environment.java @@ -382,6 +382,11 @@ public class Environment { } /** {@hide} */ + public static File getDataStagingDirectory(String volumeUuid) { + return new File(getDataDirectory(volumeUuid), "staging"); + } + + /** {@hide} */ public static File getDataUserCeDirectory(String volumeUuid) { return new File(getDataDirectory(volumeUuid), "user"); } diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 66eae5e42378..7ca39df39bb7 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -209,8 +209,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements synchronized (mSessions) { readSessionsLocked(); - reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL, false /*isInstant*/); - reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL, true /*isInstant*/); + reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL); final ArraySet<File> unclaimedIcons = newArraySet( mSessionsDir.listFiles()); @@ -230,8 +229,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } @GuardedBy("mSessions") - private void reconcileStagesLocked(String volumeUuid, boolean isEphemeral) { - final File stagingDir = buildStagingDir(volumeUuid, isEphemeral); + private void reconcileStagesLocked(String volumeUuid) { + final File stagingDir = getTmpSessionDir(volumeUuid); final ArraySet<File> unclaimedStages = newArraySet( stagingDir.listFiles(sStageFilter)); @@ -252,7 +251,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements public void onPrivateVolumeMounted(String volumeUuid) { synchronized (mSessions) { - reconcileStagesLocked(volumeUuid, false /*isInstant*/); + reconcileStagesLocked(volumeUuid); } } @@ -269,9 +268,9 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements try { final int sessionId = allocateSessionIdLocked(); mLegacySessions.put(sessionId, true); - final File stageDir = buildStageDir(volumeUuid, sessionId, isEphemeral); - prepareStageDir(stageDir); - return stageDir; + final File sessionStageDir = buildTmpSessionDir(sessionId, volumeUuid); + prepareStageDir(sessionStageDir); + return sessionStageDir; } catch (IllegalStateException e) { throw new IOException(e); } @@ -526,9 +525,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements String stageCid = null; if (!params.isMultiPackage) { if ((params.installFlags & PackageManager.INSTALL_INTERNAL) != 0) { - final boolean isInstant = - (params.installFlags & PackageManager.INSTALL_INSTANT_APP) != 0; - stageDir = buildStageDir(params.volumeUuid, sessionId, isInstant); + stageDir = buildSessionDir(sessionId, params); } else { stageCid = buildExternalStageCid(sessionId); } @@ -634,13 +631,21 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements throw new IllegalStateException("Failed to allocate session ID"); } - private File buildStagingDir(String volumeUuid, boolean isEphemeral) { + private File getTmpSessionDir(String volumeUuid) { return Environment.getDataAppDirectory(volumeUuid); } - private File buildStageDir(String volumeUuid, int sessionId, boolean isEphemeral) { - final File stagingDir = buildStagingDir(volumeUuid, isEphemeral); - return new File(stagingDir, "vmdl" + sessionId + ".tmp"); + private File buildTmpSessionDir(int sessionId, String volumeUuid) { + final File sessionStagingDir = getTmpSessionDir(volumeUuid); + return new File(sessionStagingDir, "vmdl" + sessionId + ".tmp"); + } + + private File buildSessionDir(int sessionId, SessionParams params) { + if (params.isStaged) { + final File sessionStagingDir = Environment.getDataStagingDirectory(params.volumeUuid); + return new File(sessionStagingDir, "session_" + sessionId); + } + return buildTmpSessionDir(sessionId, params.volumeUuid); } static void prepareStageDir(File stageDir) throws IOException { diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index d290f3f34909..795f655384e5 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -978,18 +978,18 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // Read transfers from the original owner stay open, but as the session's data // cannot be modified anymore, there is no leak of information. - if (!params.isMultiPackage) { + // For staged sessions, the validation is performed by StagingManager. + if (!params.isMultiPackage && !params.isStaged) { final PackageInfo pkgInfo = mPm.getPackageInfo( params.appPackageName, PackageManager.GET_SIGNATURES | PackageManager.MATCH_STATIC_SHARED_LIBRARIES /*flags*/, userId); resolveStageDirLocked(); - // Verify that stage looks sane with respect to existing application. - // This currently only ensures packageName, versionCode, and certificate - // consistency. try { if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) { + // TODO(b/118865310): Remove this when APEX validation is done via + // StagingManager. validateApexInstallLocked(pkgInfo); } else { // Verify that stage looks sane with respect to existing application. @@ -1062,16 +1062,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private void commitLocked() throws PackageManagerException { + if (params.isStaged) { + mStagingManager.commitSession(this); + destroyInternal(); + dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null); + return; + } final PackageManagerService.ActiveInstallSession committingSession = makeSessionActiveLocked(); if (committingSession == null) { return; } - if (isStaged()) { - mStagingManager.commitSession(this); - dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null); - return; - } if (isMultiPackage()) { final int[] childSessionIds = getChildSessionIds(); List<PackageManagerService.ActiveInstallSession> childSessions = @@ -1984,7 +1985,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { bridge.forceClose(); } } - if (stageDir != null) { + // For staged sessions, we don't delete the directory where the packages have been copied, + // since these packages are supposed to be read on reboot. StagingManager is in charge of + // deleting these dirs when the staged session has reached a final state. + // TODO(b/118865310): Implement packageDir deletion in StagingManager. + if (stageDir != null && !params.isStaged) { try { mPm.mInstaller.rmPackageDir(stageDir.getAbsolutePath()); } catch (InstallerException ignored) { diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index ac9c6ef57101..2e9d26a0a0ca 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -2293,6 +2293,9 @@ class PackageManagerShellCommand extends ShellCommand { break; case "--apex": sessionParams.installFlags |= PackageManager.INSTALL_APEX; + // TODO(b/118865310): APEX packages should always imply + // sessionParams.isStaged(). Enforce this when the staged + // install workflow is complete. break; case "--multi-package": sessionParams.setMultiPackage(); @@ -2588,7 +2591,7 @@ class PackageManagerShellCommand extends ShellCommand { try { session = new PackageInstaller.Session( mInterface.getPackageInstaller().openSession(sessionId)); - if (!session.isMultiPackage()) { + if (!session.isMultiPackage() && !session.isStaged()) { // Sanity check that all .dm files match an apk. // (The installer does not support standalone .dm files and will not process them.) try { |