1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.pm; 18 19 import static org.junit.Assert.assertThrows; 20 import static org.mockito.ArgumentMatchers.any; 21 import static org.mockito.ArgumentMatchers.anyInt; 22 import static org.mockito.ArgumentMatchers.anyString; 23 import static org.mockito.Mockito.mock; 24 import static org.mockito.Mockito.never; 25 import static org.mockito.Mockito.times; 26 import static org.mockito.Mockito.verify; 27 import static org.mockito.Mockito.when; 28 29 import android.content.pm.PackageInstaller; 30 import android.content.pm.PackageManager; 31 import android.platform.test.annotations.Presubmit; 32 33 import org.junit.Test; 34 import org.junit.runner.RunWith; 35 import org.junit.runners.JUnit4; 36 37 import java.util.function.Predicate; 38 39 @Presubmit 40 @RunWith(JUnit4.class) 41 public class PackageSessionVerifierTest { 42 private PackageSessionVerifier mSessionVerifier = new PackageSessionVerifier(); 43 44 @Test checkRebootlessApex()45 public void checkRebootlessApex() throws Exception { 46 StagingManager.StagedSession session1 = createStagedSession(111, "com.foo", 1); 47 mSessionVerifier.storeSession(session1); 48 49 // Should throw for package name conflicts 50 PackageInstallerSession session2 = createSession(false, true, "com.foo"); 51 assertThrows(PackageManagerException.class, 52 () -> mSessionVerifier.checkRebootlessApex(session2)); 53 54 // Shouldn't throw if no package name conflicts 55 PackageInstallerSession session3 = createSession(false, true, "com.bar"); 56 mSessionVerifier.checkRebootlessApex(session3); 57 } 58 59 @Test checkActiveSessions()60 public void checkActiveSessions() throws Exception { 61 StagingManager.StagedSession session1 = createStagedSession(111, "com.foo", 1); 62 mSessionVerifier.storeSession(session1); 63 // Shouldn't throw for a single session no matter if supporting checkpoint or not 64 mSessionVerifier.checkActiveSessions(true); 65 mSessionVerifier.checkActiveSessions(false); 66 67 // Now we have multiple active sessions 68 StagingManager.StagedSession session2 = createStagedSession(222, "com.bar", 2); 69 mSessionVerifier.storeSession(session2); 70 // Shouldn't throw if supporting checkpoint 71 mSessionVerifier.checkActiveSessions(true); 72 // Should throw if not supporting checkpoint 73 assertThrows(PackageManagerException.class, 74 () -> mSessionVerifier.checkActiveSessions(false)); 75 } 76 77 @Test checkRollbacks()78 public void checkRollbacks() throws Exception { 79 StagingManager.StagedSession session1 = createStagedSession(111, "com.foo", 1); 80 StagingManager.StagedSession session2 = createStagedSession(222, "com.bar", 2); 81 StagingManager.StagedSession session3 = createStagedSession(333, "com.baz", 3); 82 session2.sessionParams().setInstallReason(PackageManager.INSTALL_REASON_ROLLBACK); 83 session3.sessionParams().setInstallReason(PackageManager.INSTALL_REASON_ROLLBACK); 84 when(session2.isDestroyed()).thenReturn(true); 85 mSessionVerifier.storeSession(session1); 86 mSessionVerifier.storeSession(session2); 87 mSessionVerifier.storeSession(session3); 88 89 // Non-rollback session shouldn't be failed by a destroyed session 90 mSessionVerifier.checkRollbacks(session2); 91 verify(session1, never()).setSessionFailed(anyInt(), anyString()); 92 93 // Non-rollback session should fail 94 mSessionVerifier.checkRollbacks(session3); 95 verify(session1, times(1)).setSessionFailed(anyInt(), anyString()); 96 97 // Yet another non-rollback session should fail 98 StagingManager.StagedSession session4 = createStagedSession(444, "com.fur", 4); 99 assertThrows(PackageManagerException.class, 100 () -> mSessionVerifier.checkRollbacks(session4)); 101 } 102 103 @Test checkOverlaps()104 public void checkOverlaps() throws Exception { 105 StagingManager.StagedSession session1 = createStagedSession(111, "com.foo", 1); 106 StagingManager.StagedSession session2 = createStagedSession(222, "com.foo", 2); 107 mSessionVerifier.storeSession(session1); 108 mSessionVerifier.storeSession(session2); 109 // No exception should be thrown for the earlier session should not fail 110 mSessionVerifier.checkOverlaps(session1, session1); 111 // Later session should fail 112 verify(session2, times(1)).setSessionFailed(anyInt(), anyString()); 113 // Yet another later session should fail 114 StagingManager.StagedSession session3 = createStagedSession(333, "com.foo", 3); 115 assertThrows(PackageManagerException.class, 116 () -> mSessionVerifier.checkOverlaps(session3, session3)); 117 // session4 is earlier than session1, but it shouldn't fail session1 118 StagingManager.StagedSession session4 = createStagedSession(444, "com.foo", 0); 119 when(session4.isDestroyed()).thenReturn(true); 120 mSessionVerifier.checkOverlaps(session4, session4); 121 verify(session1, never()).setSessionFailed(anyInt(), anyString()); 122 } 123 createSession(boolean isStaged, boolean isApex, String packageName)124 private PackageInstallerSession createSession(boolean isStaged, boolean isApex, 125 String packageName) { 126 PackageInstallerSession session = mock(PackageInstallerSession.class); 127 when(session.isStaged()).thenReturn(isStaged); 128 when(session.isApexSession()).thenReturn(isApex); 129 when(session.getPackageName()).thenReturn(packageName); 130 return session; 131 } 132 createStagedSession(int sessionId, String packageName, long committedMillis)133 private StagingManager.StagedSession createStagedSession(int sessionId, String packageName, 134 long committedMillis) { 135 StagingManager.StagedSession session = mock(StagingManager.StagedSession.class); 136 when(session.sessionId()).thenReturn(sessionId); 137 when(session.getPackageName()).thenReturn(packageName); 138 when(session.getCommittedMillis()).thenReturn(committedMillis); 139 when(session.sessionContains(any())).then(invocation -> { 140 Predicate<StagingManager.StagedSession> filter = invocation.getArgument(0); 141 return filter.test(session); 142 }); 143 PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( 144 PackageInstaller.SessionParams.MODE_FULL_INSTALL); 145 when(session.sessionParams()).thenReturn(params); 146 return session; 147 } 148 } 149