Loading services/core/java/com/android/server/pm/PackageInstallerService.java +2 −2 Original line number Diff line number Diff line Loading @@ -747,8 +747,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements installerAttributionTag); session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this, mInstallThread.getLooper(), mStagingManager, sessionId, userId, callingUid, installSource, params, createdMillis, stageDir, stageCid, null, null, false, false, false, false, null, SessionInfo.INVALID_ID, false, false, false, installSource, params, createdMillis, 0L, stageDir, stageCid, null, null, false, false, false, false, null, SessionInfo.INVALID_ID, false, false, false, SessionInfo.STAGED_SESSION_NO_ERROR, ""); synchronized (mSessions) { Loading services/core/java/com/android/server/pm/PackageInstallerSession.java +25 −5 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import static android.system.OsConstants.O_CREAT; import static android.system.OsConstants.O_RDONLY; import static android.system.OsConstants.O_WRONLY; import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; import static com.android.internal.util.XmlUtils.readBitmapAttribute; import static com.android.internal.util.XmlUtils.readByteArrayAttribute; import static com.android.internal.util.XmlUtils.readStringAttribute; Loading Loading @@ -132,6 +133,7 @@ import android.util.apk.ApkSignatureVerifier; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.NativeLibraryHelper; import com.android.internal.content.PackageHelper; import com.android.internal.messages.nano.SystemMessageProto; Loading Loading @@ -201,6 +203,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { "installOriginatingPackageName"; private static final String ATTR_CREATED_MILLIS = "createdMillis"; private static final String ATTR_UPDATED_MILLIS = "updatedMillis"; private static final String ATTR_COMMITTED_MILLIS = "committedMillis"; private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir"; private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid"; private static final String ATTR_PREPARED = "prepared"; Loading Loading @@ -291,6 +294,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private long updatedMillis; /** Timestamp of the time this session is committed */ @GuardedBy("mLock") private long committedMillis; /** Uid of the creator of this session. */ private final int mOriginalInstallerUid; Loading Loading @@ -625,7 +632,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { Context context, PackageManagerService pm, PackageSessionProvider sessionProvider, Looper looper, StagingManager stagingManager, int sessionId, int userId, int installerUid, @NonNull InstallSource installSource, SessionParams params, long createdMillis, SessionParams params, long createdMillis, long committedMillis, File stageDir, String stageCid, InstallationFile[] files, ArrayMap<String, List<CertifiedChecksum>> checksums, boolean prepared, boolean committed, boolean destroyed, boolean sealed, Loading @@ -648,6 +655,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { this.params = params; this.createdMillis = createdMillis; this.updatedMillis = createdMillis; this.committedMillis = committedMillis; this.stageDir = stageDir; this.stageCid = stageCid; this.mShouldBeSealed = sealed; Loading Loading @@ -1641,6 +1649,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mActiveCount.incrementAndGet(); mCommitted = true; committedMillis = System.currentTimeMillis(); } return true; } catch (PackageManagerException e) { Loading Loading @@ -2963,7 +2972,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { /** * @return the package name of this session */ String getPackageName() { @VisibleForTesting(visibility = PACKAGE) public String getPackageName() { synchronized (mLock) { return mPackageName; } Loading @@ -2978,6 +2988,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } long getCommittedMillis() { synchronized (mLock) { return committedMillis; } } String getInstallerPackageName() { return getInstallSource().installerPackageName; } Loading Loading @@ -3923,6 +3939,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { pw.printPair("mInstallerUid", mInstallerUid); pw.printPair("createdMillis", createdMillis); pw.printPair("updatedMillis", updatedMillis); pw.printPair("committedMillis", committedMillis); pw.printPair("stageDir", stageDir); pw.printPair("stageCid", stageCid); pw.println(); Loading Loading @@ -4099,6 +4116,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mInstallSource.originatingPackageName); out.attributeLong(null, ATTR_CREATED_MILLIS, createdMillis); out.attributeLong(null, ATTR_UPDATED_MILLIS, updatedMillis); out.attributeLong(null, ATTR_COMMITTED_MILLIS, committedMillis); if (stageDir != null) { writeStringAttribute(out, ATTR_SESSION_STAGE_DIR, stageDir.getAbsolutePath()); Loading Loading @@ -4252,6 +4270,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { readStringAttribute(in, ATTR_ORIGINATING_PACKAGE_NAME); final long createdMillis = in.getAttributeLong(null, ATTR_CREATED_MILLIS); long updatedMillis = in.getAttributeLong(null, ATTR_UPDATED_MILLIS); final long committedMillis = in.getAttributeLong(null, ATTR_COMMITTED_MILLIS, 0L); final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR); final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null; final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID); Loading Loading @@ -4395,8 +4414,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { installOriginatingPackageName, installerPackageName, installerAttributionTag); return new PackageInstallerSession(callback, context, pm, sessionProvider, installerThread, stagingManager, sessionId, userId, installerUid, installSource, params, createdMillis, stageDir, stageCid, fileArray, checksums, prepared, committed, destroyed, sealed, childSessionIdsArray, parentSessionId, isReady, isFailed, isApplied, stagedSessionErrorCode, stagedSessionErrorMessage); installSource, params, createdMillis, committedMillis, stageDir, stageCid, fileArray, checksums, prepared, committed, destroyed, sealed, childSessionIdsArray, parentSessionId, isReady, isFailed, isApplied, stagedSessionErrorCode, stagedSessionErrorMessage); } } services/core/java/com/android/server/pm/StagingManager.java +12 −2 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ import android.util.SparseArray; import android.util.apk.ApkSignatureVerifier; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.PackageHelper; import com.android.internal.os.BackgroundThread; import com.android.server.LocalServices; Loading Loading @@ -720,7 +721,8 @@ public class StagingManager { * </ul> * @throws PackageManagerException if session fails the check */ private void checkNonOverlappingWithStagedSessions(@NonNull PackageInstallerSession session) @VisibleForTesting void checkNonOverlappingWithStagedSessions(@NonNull PackageInstallerSession session) throws PackageManagerException { if (session.isMultiPackage()) { // We cannot say a parent session overlaps until we process its children Loading @@ -747,6 +749,13 @@ public class StagingManager { continue; } if (stagedSession.getCommittedMillis() > session.getCommittedMillis()) { // Ignore sessions that are committed after the provided session. When there are // overlaps between sessions, we will fail the one committed later instead of // the earlier one. continue; } // From here on, stagedSession is a parent active staged session // Check if session is one of the active sessions Loading Loading @@ -793,7 +802,8 @@ public class StagingManager { } } private void createSession(@NonNull PackageInstallerSession sessionInfo) { @VisibleForTesting void createSession(@NonNull PackageInstallerSession sessionInfo) { synchronized (mStagedSessions) { mStagedSessions.append(sessionInfo.sessionId, sessionInfo); } Loading services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java +1 −0 Original line number Diff line number Diff line Loading @@ -173,6 +173,7 @@ public class PackageInstallerSessionTest { /* installSource */ installSource, /* sessionParams */ params, /* createdMillis */ 0L, /* committedMillis */ 0L, /* stageDir */ mTmpDir, /* stageCid */ null, /* files */ null, Loading services/tests/servicestests/src/com/android/server/pm/StagingManagerTest.java 0 → 100644 +128 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.pm; import android.content.Context; import android.content.pm.PackageInstaller; import android.os.storage.StorageManager; import android.platform.test.annotations.Presubmit; import com.android.internal.os.BackgroundThread; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.io.File; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import static org.testng.Assert.assertThrows; @Presubmit @RunWith(JUnit4.class) public class StagingManagerTest { @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder(); private File mTmpDir; private StagingManager mStagingManager; @Before public void setup() throws Exception { MockitoAnnotations.initMocks(this); StorageManager storageManager = Mockito.mock(StorageManager.class); Context context = Mockito.mock(Context.class); when(storageManager.isCheckpointSupported()).thenReturn(true); when(context.getSystemService(eq(Context.POWER_SERVICE))).thenReturn(null); when(context.getSystemService(eq(Context.STORAGE_SERVICE))).thenReturn(storageManager); mTmpDir = mTemporaryFolder.newFolder("StagingManagerTest"); mStagingManager = new StagingManager(context, null); } /** * Tests that sessions committed later shouldn't cause earlier ones to fail the overlapping * check. */ @Test public void checkNonOverlappingWithStagedSessions_laterSessionShouldNotFailEarlierOnes() throws Exception { // Create 2 sessions with overlapping packages PackageInstallerSession session1 = createSession(111, "com.foo", 1); PackageInstallerSession session2 = createSession(222, "com.foo", 2); mStagingManager.createSession(session1); mStagingManager.createSession(session2); // Session1 should not fail in spite of the overlapping packages mStagingManager.checkNonOverlappingWithStagedSessions(session1); // Session2 should fail due to overlapping packages assertThrows(PackageManagerException.class, () -> mStagingManager.checkNonOverlappingWithStagedSessions(session2)); } private PackageInstallerSession createSession(int sessionId, String packageName, long committedMillis) { PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( PackageInstaller.SessionParams.MODE_FULL_INSTALL); params.isStaged = true; InstallSource installSource = InstallSource.create("testInstallInitiator", "testInstallOriginator", "testInstaller", "testAttributionTag"); PackageInstallerSession session = new PackageInstallerSession( /* callback */ null, /* context */ null, /* pm */ null, /* sessionProvider */ null, /* looper */ BackgroundThread.getHandler().getLooper(), /* stagingManager */ null, /* sessionId */ sessionId, /* userId */ 456, /* installerUid */ -1, /* installSource */ installSource, /* sessionParams */ params, /* createdMillis */ 0L, /* committedMillis */ committedMillis, /* stageDir */ mTmpDir, /* stageCid */ null, /* files */ null, /* checksums */ null, /* prepared */ true, /* committed */ true, /* destroyed */ false, /* sealed */ false, // Setting to true would trigger some PM logic. /* childSessionIds */ null, /* parentSessionId */ -1, /* isReady */ false, /* isFailed */ false, /* isApplied */false, /* stagedSessionErrorCode */ PackageInstaller.SessionInfo.STAGED_SESSION_NO_ERROR, /* stagedSessionErrorMessage */ "no error"); session = spy(session); doReturn(packageName).when(session).getPackageName(); return session; } } Loading
services/core/java/com/android/server/pm/PackageInstallerService.java +2 −2 Original line number Diff line number Diff line Loading @@ -747,8 +747,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements installerAttributionTag); session = new PackageInstallerSession(mInternalCallback, mContext, mPm, this, mInstallThread.getLooper(), mStagingManager, sessionId, userId, callingUid, installSource, params, createdMillis, stageDir, stageCid, null, null, false, false, false, false, null, SessionInfo.INVALID_ID, false, false, false, installSource, params, createdMillis, 0L, stageDir, stageCid, null, null, false, false, false, false, null, SessionInfo.INVALID_ID, false, false, false, SessionInfo.STAGED_SESSION_NO_ERROR, ""); synchronized (mSessions) { Loading
services/core/java/com/android/server/pm/PackageInstallerSession.java +25 −5 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import static android.system.OsConstants.O_CREAT; import static android.system.OsConstants.O_RDONLY; import static android.system.OsConstants.O_WRONLY; import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; import static com.android.internal.util.XmlUtils.readBitmapAttribute; import static com.android.internal.util.XmlUtils.readByteArrayAttribute; import static com.android.internal.util.XmlUtils.readStringAttribute; Loading Loading @@ -132,6 +133,7 @@ import android.util.apk.ApkSignatureVerifier; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.NativeLibraryHelper; import com.android.internal.content.PackageHelper; import com.android.internal.messages.nano.SystemMessageProto; Loading Loading @@ -201,6 +203,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { "installOriginatingPackageName"; private static final String ATTR_CREATED_MILLIS = "createdMillis"; private static final String ATTR_UPDATED_MILLIS = "updatedMillis"; private static final String ATTR_COMMITTED_MILLIS = "committedMillis"; private static final String ATTR_SESSION_STAGE_DIR = "sessionStageDir"; private static final String ATTR_SESSION_STAGE_CID = "sessionStageCid"; private static final String ATTR_PREPARED = "prepared"; Loading Loading @@ -291,6 +294,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @GuardedBy("mLock") private long updatedMillis; /** Timestamp of the time this session is committed */ @GuardedBy("mLock") private long committedMillis; /** Uid of the creator of this session. */ private final int mOriginalInstallerUid; Loading Loading @@ -625,7 +632,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { Context context, PackageManagerService pm, PackageSessionProvider sessionProvider, Looper looper, StagingManager stagingManager, int sessionId, int userId, int installerUid, @NonNull InstallSource installSource, SessionParams params, long createdMillis, SessionParams params, long createdMillis, long committedMillis, File stageDir, String stageCid, InstallationFile[] files, ArrayMap<String, List<CertifiedChecksum>> checksums, boolean prepared, boolean committed, boolean destroyed, boolean sealed, Loading @@ -648,6 +655,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { this.params = params; this.createdMillis = createdMillis; this.updatedMillis = createdMillis; this.committedMillis = committedMillis; this.stageDir = stageDir; this.stageCid = stageCid; this.mShouldBeSealed = sealed; Loading Loading @@ -1641,6 +1649,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mActiveCount.incrementAndGet(); mCommitted = true; committedMillis = System.currentTimeMillis(); } return true; } catch (PackageManagerException e) { Loading Loading @@ -2963,7 +2972,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { /** * @return the package name of this session */ String getPackageName() { @VisibleForTesting(visibility = PACKAGE) public String getPackageName() { synchronized (mLock) { return mPackageName; } Loading @@ -2978,6 +2988,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } long getCommittedMillis() { synchronized (mLock) { return committedMillis; } } String getInstallerPackageName() { return getInstallSource().installerPackageName; } Loading Loading @@ -3923,6 +3939,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { pw.printPair("mInstallerUid", mInstallerUid); pw.printPair("createdMillis", createdMillis); pw.printPair("updatedMillis", updatedMillis); pw.printPair("committedMillis", committedMillis); pw.printPair("stageDir", stageDir); pw.printPair("stageCid", stageCid); pw.println(); Loading Loading @@ -4099,6 +4116,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mInstallSource.originatingPackageName); out.attributeLong(null, ATTR_CREATED_MILLIS, createdMillis); out.attributeLong(null, ATTR_UPDATED_MILLIS, updatedMillis); out.attributeLong(null, ATTR_COMMITTED_MILLIS, committedMillis); if (stageDir != null) { writeStringAttribute(out, ATTR_SESSION_STAGE_DIR, stageDir.getAbsolutePath()); Loading Loading @@ -4252,6 +4270,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { readStringAttribute(in, ATTR_ORIGINATING_PACKAGE_NAME); final long createdMillis = in.getAttributeLong(null, ATTR_CREATED_MILLIS); long updatedMillis = in.getAttributeLong(null, ATTR_UPDATED_MILLIS); final long committedMillis = in.getAttributeLong(null, ATTR_COMMITTED_MILLIS, 0L); final String stageDirRaw = readStringAttribute(in, ATTR_SESSION_STAGE_DIR); final File stageDir = (stageDirRaw != null) ? new File(stageDirRaw) : null; final String stageCid = readStringAttribute(in, ATTR_SESSION_STAGE_CID); Loading Loading @@ -4395,8 +4414,9 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { installOriginatingPackageName, installerPackageName, installerAttributionTag); return new PackageInstallerSession(callback, context, pm, sessionProvider, installerThread, stagingManager, sessionId, userId, installerUid, installSource, params, createdMillis, stageDir, stageCid, fileArray, checksums, prepared, committed, destroyed, sealed, childSessionIdsArray, parentSessionId, isReady, isFailed, isApplied, stagedSessionErrorCode, stagedSessionErrorMessage); installSource, params, createdMillis, committedMillis, stageDir, stageCid, fileArray, checksums, prepared, committed, destroyed, sealed, childSessionIdsArray, parentSessionId, isReady, isFailed, isApplied, stagedSessionErrorCode, stagedSessionErrorMessage); } }
services/core/java/com/android/server/pm/StagingManager.java +12 −2 Original line number Diff line number Diff line Loading @@ -59,6 +59,7 @@ import android.util.SparseArray; import android.util.apk.ApkSignatureVerifier; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.PackageHelper; import com.android.internal.os.BackgroundThread; import com.android.server.LocalServices; Loading Loading @@ -720,7 +721,8 @@ public class StagingManager { * </ul> * @throws PackageManagerException if session fails the check */ private void checkNonOverlappingWithStagedSessions(@NonNull PackageInstallerSession session) @VisibleForTesting void checkNonOverlappingWithStagedSessions(@NonNull PackageInstallerSession session) throws PackageManagerException { if (session.isMultiPackage()) { // We cannot say a parent session overlaps until we process its children Loading @@ -747,6 +749,13 @@ public class StagingManager { continue; } if (stagedSession.getCommittedMillis() > session.getCommittedMillis()) { // Ignore sessions that are committed after the provided session. When there are // overlaps between sessions, we will fail the one committed later instead of // the earlier one. continue; } // From here on, stagedSession is a parent active staged session // Check if session is one of the active sessions Loading Loading @@ -793,7 +802,8 @@ public class StagingManager { } } private void createSession(@NonNull PackageInstallerSession sessionInfo) { @VisibleForTesting void createSession(@NonNull PackageInstallerSession sessionInfo) { synchronized (mStagedSessions) { mStagedSessions.append(sessionInfo.sessionId, sessionInfo); } Loading
services/tests/servicestests/src/com/android/server/pm/PackageInstallerSessionTest.java +1 −0 Original line number Diff line number Diff line Loading @@ -173,6 +173,7 @@ public class PackageInstallerSessionTest { /* installSource */ installSource, /* sessionParams */ params, /* createdMillis */ 0L, /* committedMillis */ 0L, /* stageDir */ mTmpDir, /* stageCid */ null, /* files */ null, Loading
services/tests/servicestests/src/com/android/server/pm/StagingManagerTest.java 0 → 100644 +128 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.server.pm; import android.content.Context; import android.content.pm.PackageInstaller; import android.os.storage.StorageManager; import android.platform.test.annotations.Presubmit; import com.android.internal.os.BackgroundThread; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import java.io.File; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import static org.testng.Assert.assertThrows; @Presubmit @RunWith(JUnit4.class) public class StagingManagerTest { @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder(); private File mTmpDir; private StagingManager mStagingManager; @Before public void setup() throws Exception { MockitoAnnotations.initMocks(this); StorageManager storageManager = Mockito.mock(StorageManager.class); Context context = Mockito.mock(Context.class); when(storageManager.isCheckpointSupported()).thenReturn(true); when(context.getSystemService(eq(Context.POWER_SERVICE))).thenReturn(null); when(context.getSystemService(eq(Context.STORAGE_SERVICE))).thenReturn(storageManager); mTmpDir = mTemporaryFolder.newFolder("StagingManagerTest"); mStagingManager = new StagingManager(context, null); } /** * Tests that sessions committed later shouldn't cause earlier ones to fail the overlapping * check. */ @Test public void checkNonOverlappingWithStagedSessions_laterSessionShouldNotFailEarlierOnes() throws Exception { // Create 2 sessions with overlapping packages PackageInstallerSession session1 = createSession(111, "com.foo", 1); PackageInstallerSession session2 = createSession(222, "com.foo", 2); mStagingManager.createSession(session1); mStagingManager.createSession(session2); // Session1 should not fail in spite of the overlapping packages mStagingManager.checkNonOverlappingWithStagedSessions(session1); // Session2 should fail due to overlapping packages assertThrows(PackageManagerException.class, () -> mStagingManager.checkNonOverlappingWithStagedSessions(session2)); } private PackageInstallerSession createSession(int sessionId, String packageName, long committedMillis) { PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( PackageInstaller.SessionParams.MODE_FULL_INSTALL); params.isStaged = true; InstallSource installSource = InstallSource.create("testInstallInitiator", "testInstallOriginator", "testInstaller", "testAttributionTag"); PackageInstallerSession session = new PackageInstallerSession( /* callback */ null, /* context */ null, /* pm */ null, /* sessionProvider */ null, /* looper */ BackgroundThread.getHandler().getLooper(), /* stagingManager */ null, /* sessionId */ sessionId, /* userId */ 456, /* installerUid */ -1, /* installSource */ installSource, /* sessionParams */ params, /* createdMillis */ 0L, /* committedMillis */ committedMillis, /* stageDir */ mTmpDir, /* stageCid */ null, /* files */ null, /* checksums */ null, /* prepared */ true, /* committed */ true, /* destroyed */ false, /* sealed */ false, // Setting to true would trigger some PM logic. /* childSessionIds */ null, /* parentSessionId */ -1, /* isReady */ false, /* isFailed */ false, /* isApplied */false, /* stagedSessionErrorCode */ PackageInstaller.SessionInfo.STAGED_SESSION_NO_ERROR, /* stagedSessionErrorMessage */ "no error"); session = spy(session); doReturn(packageName).when(session).getPackageName(); return session; } }