diff options
15 files changed, 567 insertions, 97 deletions
diff --git a/core/api/system-current.txt b/core/api/system-current.txt index fa4fc43c3418..349d06ca8ad6 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -4170,9 +4170,11 @@ package android.content.pm { } public class PackageInstaller { + method @FlaggedApi("android.content.pm.verification_service") @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public final int getVerificationPolicy(); method @NonNull public android.content.pm.PackageInstaller.InstallInfo readInstallInfo(@NonNull java.io.File, int) throws android.content.pm.PackageInstaller.PackageParsingException; method @FlaggedApi("android.content.pm.read_install_info") @NonNull public android.content.pm.PackageInstaller.InstallInfo readInstallInfo(@NonNull android.os.ParcelFileDescriptor, @Nullable String, int) throws android.content.pm.PackageInstaller.PackageParsingException; method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setPermissionsResult(int, boolean); + method @FlaggedApi("android.content.pm.verification_service") @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public final boolean setVerificationPolicy(int); field public static final String ACTION_CONFIRM_INSTALL = "android.content.pm.action.CONFIRM_INSTALL"; field public static final String ACTION_CONFIRM_PRE_APPROVAL = "android.content.pm.action.CONFIRM_PRE_APPROVAL"; field public static final int DATA_LOADER_TYPE_INCREMENTAL = 2; // 0x2 @@ -4183,12 +4185,20 @@ package android.content.pm { field @FlaggedApi("android.content.pm.archiving") public static final String EXTRA_DELETE_FLAGS = "android.content.pm.extra.DELETE_FLAGS"; field public static final String EXTRA_LEGACY_STATUS = "android.content.pm.extra.LEGACY_STATUS"; field @Deprecated public static final String EXTRA_RESOLVED_BASE_PATH = "android.content.pm.extra.RESOLVED_BASE_PATH"; + field @FlaggedApi("android.content.pm.verification_service") public static final String EXTRA_VERIFICATION_FAILURE_REASON = "android.content.pm.extra.VERIFICATION_FAILURE_REASON"; field public static final int LOCATION_DATA_APP = 0; // 0x0 field public static final int LOCATION_MEDIA_DATA = 2; // 0x2 field public static final int LOCATION_MEDIA_OBB = 1; // 0x1 field public static final int REASON_CONFIRM_PACKAGE_CHANGE = 0; // 0x0 field public static final int REASON_OWNERSHIP_CHANGED = 1; // 0x1 field public static final int REASON_REMIND_OWNERSHIP = 2; // 0x2 + field @FlaggedApi("android.content.pm.verification_service") public static final int VERIFICATION_FAILED_REASON_NETWORK_UNAVAILABLE = 1; // 0x1 + field @FlaggedApi("android.content.pm.verification_service") public static final int VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED = 2; // 0x2 + field @FlaggedApi("android.content.pm.verification_service") public static final int VERIFICATION_FAILED_REASON_UNKNOWN = 0; // 0x0 + field @FlaggedApi("android.content.pm.verification_service") public static final int VERIFICATION_POLICY_BLOCK_FAIL_CLOSED = 3; // 0x3 + field @FlaggedApi("android.content.pm.verification_service") public static final int VERIFICATION_POLICY_BLOCK_FAIL_OPEN = 1; // 0x1 + field @FlaggedApi("android.content.pm.verification_service") public static final int VERIFICATION_POLICY_BLOCK_FAIL_WARN = 2; // 0x2 + field @FlaggedApi("android.content.pm.verification_service") public static final int VERIFICATION_POLICY_NONE = 0; // 0x0 } public static class PackageInstaller.InstallInfo { @@ -4635,12 +4645,13 @@ package android.content.pm.verify.pkg { method @NonNull public android.content.pm.SigningInfo getSigningInfo(); method @NonNull public android.net.Uri getStagedPackageUri(); method @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public long getTimeoutTime(); + method public int getVerificationPolicy(); method @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public void reportVerificationComplete(@NonNull android.content.pm.verify.pkg.VerificationStatus); method @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public void reportVerificationComplete(@NonNull android.content.pm.verify.pkg.VerificationStatus, @NonNull android.os.PersistableBundle); method @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public void reportVerificationIncomplete(int); + method @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) public boolean setVerificationPolicy(int); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.verify.pkg.VerificationSession> CREATOR; - field public static final int VERIFICATION_INCOMPLETE_NETWORK_LIMITED = 2; // 0x2 field public static final int VERIFICATION_INCOMPLETE_NETWORK_UNAVAILABLE = 1; // 0x1 field public static final int VERIFICATION_INCOMPLETE_UNKNOWN = 0; // 0x0 } diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl index 451c0e5e079a..c911326ccffd 100644 --- a/core/java/android/content/pm/IPackageInstaller.aidl +++ b/core/java/android/content/pm/IPackageInstaller.aidl @@ -93,4 +93,10 @@ interface IPackageInstaller { @JavaPassthrough(annotation="@android.annotation.RequiresPermission(anyOf={android.Manifest.permission.INSTALL_PACKAGES,android.Manifest.permission.REQUEST_INSTALL_PACKAGES})") void reportUnarchivalStatus(int unarchiveId, int status, long requiredStorageBytes, in PendingIntent userActionIntent, in UserHandle userHandle); + + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT)") + int getVerificationPolicy(); + + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT)") + boolean setVerificationPolicy(int policy); } diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index c673d5846d5d..cba7bc912666 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -62,6 +62,8 @@ import android.content.pm.parsing.PackageLite; import android.content.pm.parsing.result.ParseResult; import android.content.pm.parsing.result.ParseTypeImpl; import android.content.pm.verify.domain.DomainSet; +import android.content.pm.verify.pkg.VerificationSession; +import android.content.pm.verify.pkg.VerificationStatus; import android.graphics.Bitmap; import android.icu.util.ULocale; import android.net.Uri; @@ -418,6 +420,21 @@ public class PackageInstaller { public static final String EXTRA_WARNINGS = "android.content.pm.extra.WARNINGS"; /** + * When verification is blocked as part of the installation, additional reason for the block + * will be provided to the installer with a {@link VerificationFailedReason} as part of the + * installation result returned via the {@link IntentSender} in + * {@link Session#commit(IntentSender)}. This extra is provided only when the installation has + * failed. Installers can use this extra to check if the installation failure was caused by a + * verification failure. + * + * @hide + */ + @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) + @SystemApi + public static final String EXTRA_VERIFICATION_FAILURE_REASON = + "android.content.pm.extra.VERIFICATION_FAILURE_REASON"; + + /** * Streaming installation pending. * Caller should make sure DataLoader is able to prepare image and reinitiate the operation. * @@ -760,6 +777,90 @@ public class PackageInstaller { @Retention(RetentionPolicy.SOURCE) public @interface UnarchivalStatus {} + /** + * Verification failed because of unknown reasons, such as when the verifier times out or cannot + * be connected. It can also corresponds to the status of + * {@link VerificationSession#VERIFICATION_INCOMPLETE_UNKNOWN} reported by the verifier via + * {@link VerificationSession#reportVerificationIncomplete(int)}. + * @hide + */ + @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) + @SystemApi + public static final int VERIFICATION_FAILED_REASON_UNKNOWN = 0; + + /** + * Verification failed because the network is unavailable. This corresponds to the status of + * {@link VerificationSession#VERIFICATION_INCOMPLETE_NETWORK_UNAVAILABLE} reported by the + * verifier via {@link VerificationSession#reportVerificationIncomplete(int)}. + * + * @hide + */ + @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) + @SystemApi + public static final int VERIFICATION_FAILED_REASON_NETWORK_UNAVAILABLE = 1; + + /** + * Verification failed because the package is blocked, as reported by the verifier via + * {@link VerificationSession#reportVerificationComplete(VerificationStatus)} or + * {@link VerificationSession#reportVerificationComplete(VerificationStatus, PersistableBundle)} + * @hide + */ + @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) + @SystemApi + public static final int VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED = 2; + + /** + * @hide + */ + @IntDef(value = { + VERIFICATION_FAILED_REASON_UNKNOWN, + VERIFICATION_FAILED_REASON_NETWORK_UNAVAILABLE, + VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED, + }) + public @interface VerificationFailedReason { + } + + /** + * Do not block installs, regardless of verification status. + * @hide + */ + @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) + @SystemApi + public static final int VERIFICATION_POLICY_NONE = 0; // platform default + /** + * Only block installations on {@link #VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED}. + * @hide + */ + @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) + @SystemApi + public static final int VERIFICATION_POLICY_BLOCK_FAIL_OPEN = 1; + /** + * Only block installations on {@link #VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED} and ask the + * user if they'd like to install anyway when the verification is blocked for other reason. + * @hide + */ + @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) + @SystemApi + public static final int VERIFICATION_POLICY_BLOCK_FAIL_WARN = 2; + /** + * Block installations whose verification status is blocked for any reason. + * @hide + */ + @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) + @SystemApi + public static final int VERIFICATION_POLICY_BLOCK_FAIL_CLOSED = 3; + /** + * @hide + */ + @IntDef(value = { + VERIFICATION_POLICY_NONE, + VERIFICATION_POLICY_BLOCK_FAIL_OPEN, + VERIFICATION_POLICY_BLOCK_FAIL_WARN, + VERIFICATION_POLICY_BLOCK_FAIL_CLOSED, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface VerificationPolicy { + } /** Default set of checksums - includes all available checksums. * @see Session#requestChecksums */ @@ -1503,6 +1604,40 @@ public class PackageInstaller { } /** + * Return the current verification enforcement policy. This may only be called by the + * package currently set by the system as the verifier agent. + * @hide + */ + @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) + @SystemApi + @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) + public final @VerificationPolicy int getVerificationPolicy() { + try { + return mInstaller.getVerificationPolicy(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Set the current verification enforcement policy which will be applied to all the future + * installation sessions. This may only be called by the package currently set by the system as + * the verifier agent. + * @hide + * @return whether the new policy was successfully set. + */ + @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE) + @SystemApi + @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) + public final boolean setVerificationPolicy(@VerificationPolicy int policy) { + try { + return mInstaller.setVerificationPolicy(policy); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * An installation that is being actively staged. For an install to succeed, * all existing and new packages must have identical package names, version * codes, and signing certificates. diff --git a/core/java/android/content/pm/verify/pkg/IVerificationSessionInterface.aidl b/core/java/android/content/pm/verify/pkg/IVerificationSessionInterface.aidl index 7a9484abd1b1..036c1e69cb0d 100644 --- a/core/java/android/content/pm/verify/pkg/IVerificationSessionInterface.aidl +++ b/core/java/android/content/pm/verify/pkg/IVerificationSessionInterface.aidl @@ -25,4 +25,6 @@ interface IVerificationSessionInterface { long getTimeoutTime(int verificationId); @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT)") long extendTimeRemaining(int verificationId, long additionalMs); + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT)") + boolean setVerificationPolicy(int verificationId, int policy); }
\ No newline at end of file diff --git a/core/java/android/content/pm/verify/pkg/VerificationSession.java b/core/java/android/content/pm/verify/pkg/VerificationSession.java index 70b4a022f521..f393be829aed 100644 --- a/core/java/android/content/pm/verify/pkg/VerificationSession.java +++ b/core/java/android/content/pm/verify/pkg/VerificationSession.java @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.content.pm.Flags; +import android.content.pm.PackageInstaller; import android.content.pm.SharedLibraryInfo; import android.content.pm.SigningInfo; import android.net.Uri; @@ -52,17 +53,12 @@ public final class VerificationSession implements Parcelable { * The verification cannot be completed because the network is unavailable. */ public static final int VERIFICATION_INCOMPLETE_NETWORK_UNAVAILABLE = 1; - /** - * The verification cannot be completed because the network is limited. - */ - public static final int VERIFICATION_INCOMPLETE_NETWORK_LIMITED = 2; /** * @hide */ @IntDef(prefix = {"VERIFICATION_INCOMPLETE_"}, value = { VERIFICATION_INCOMPLETE_NETWORK_UNAVAILABLE, - VERIFICATION_INCOMPLETE_NETWORK_LIMITED, VERIFICATION_INCOMPLETE_UNKNOWN, }) @Retention(RetentionPolicy.SOURCE) @@ -85,6 +81,15 @@ public final class VerificationSession implements Parcelable { private final IVerificationSessionInterface mSession; @NonNull private final IVerificationSessionCallback mCallback; + /** + * The current policy that is active for the session. It might not be + * the same as the original policy that was initially assigned for this verification session, + * because the active policy can be overridden by {@link #setVerificationPolicy(int)}. + * <p>To improve the latency, store the original policy value and any changes made to it, + * so that {@link #getVerificationPolicy()} does not need to make a binder call to retrieve the + * currently active policy.</p> + */ + private volatile @PackageInstaller.VerificationPolicy int mVerificationPolicy; /** * Constructor used by the system to describe the details of a verification session. @@ -94,6 +99,7 @@ public final class VerificationSession implements Parcelable { @NonNull Uri stagedPackageUri, @NonNull SigningInfo signingInfo, @NonNull List<SharedLibraryInfo> declaredLibraries, @NonNull PersistableBundle extensionParams, + @PackageInstaller.VerificationPolicy int defaultPolicy, @NonNull IVerificationSessionInterface session, @NonNull IVerificationSessionCallback callback) { mId = id; @@ -103,6 +109,7 @@ public final class VerificationSession implements Parcelable { mSigningInfo = signingInfo; mDeclaredLibraries = declaredLibraries; mExtensionParams = extensionParams; + mVerificationPolicy = defaultPolicy; mSession = session; mCallback = callback; } @@ -144,7 +151,7 @@ public final class VerificationSession implements Parcelable { /** * Returns a mapping of any shared libraries declared in the manifest - * to the {@link SharedLibraryInfo#Type} that is declared. This will be an empty + * to the {@link SharedLibraryInfo.Type} that is declared. This will be an empty * map if no shared libraries are declared by the package. */ @NonNull @@ -174,6 +181,39 @@ public final class VerificationSession implements Parcelable { } /** + * Return the current policy that is active for this session. + * <p>If the policy for this session has been changed by {@link #setVerificationPolicy}, + * the return value of this method is the current policy that is active for this session. + * Otherwise, the return value is the same as the initial policy that was assigned to the + * session when it was first created.</p> + */ + public @PackageInstaller.VerificationPolicy int getVerificationPolicy() { + return mVerificationPolicy; + } + + /** + * Override the verification policy for this session. + * @return True if the override was successful, False otherwise. + */ + @RequiresPermission(android.Manifest.permission.VERIFICATION_AGENT) + public boolean setVerificationPolicy(@PackageInstaller.VerificationPolicy int policy) { + if (mVerificationPolicy == policy) { + // No effective policy change + return true; + } + try { + if (mSession.setVerificationPolicy(mId, policy)) { + mVerificationPolicy = policy; + return true; + } else { + return false; + } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Extend the timeout for this session by the provided additionalMs to * fetch relevant information over the network or wait for the network. * This may be called multiple times. If the request would bypass any max @@ -239,6 +279,7 @@ public final class VerificationSession implements Parcelable { mSigningInfo = SigningInfo.CREATOR.createFromParcel(in); mDeclaredLibraries = in.createTypedArrayList(SharedLibraryInfo.CREATOR); mExtensionParams = in.readPersistableBundle(getClass().getClassLoader()); + mVerificationPolicy = in.readInt(); mSession = IVerificationSessionInterface.Stub.asInterface(in.readStrongBinder()); mCallback = IVerificationSessionCallback.Stub.asInterface(in.readStrongBinder()); } @@ -257,6 +298,7 @@ public final class VerificationSession implements Parcelable { mSigningInfo.writeToParcel(dest, flags); dest.writeTypedList(mDeclaredLibraries); dest.writePersistableBundle(mExtensionParams); + dest.writeInt(mVerificationPolicy); dest.writeStrongBinder(mSession.asBinder()); dest.writeStrongBinder(mCallback.asBinder()); } diff --git a/core/tests/coretests/src/android/content/pm/verify/VerificationSessionTest.java b/core/tests/coretests/src/android/content/pm/verify/VerificationSessionTest.java index 987f68d4f9e1..80255c5f6600 100644 --- a/core/tests/coretests/src/android/content/pm/verify/VerificationSessionTest.java +++ b/core/tests/coretests/src/android/content/pm/verify/VerificationSessionTest.java @@ -16,6 +16,9 @@ package android.content.pm.verify; +import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_CLOSED; +import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_WARN; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; @@ -23,6 +26,8 @@ import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import android.content.pm.SharedLibraryInfo; @@ -73,6 +78,7 @@ public class VerificationSessionTest { private static final long TEST_EXTEND_TIME = 2000L; private static final String TEST_KEY = "test key"; private static final String TEST_VALUE = "test value"; + private static final int TEST_POLICY = VERIFICATION_POLICY_BLOCK_FAIL_CLOSED; private final ArrayList<SharedLibraryInfo> mTestDeclaredLibraries = new ArrayList<>(); private final PersistableBundle mTestExtensionParams = new PersistableBundle(); @@ -90,7 +96,7 @@ public class VerificationSessionTest { mTestExtensionParams.putString(TEST_KEY, TEST_VALUE); mTestSession = new VerificationSession(TEST_ID, TEST_INSTALL_SESSION_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, TEST_SIGNING_INFO, mTestDeclaredLibraries, - mTestExtensionParams, mTestSessionInterface, mTestCallback); + mTestExtensionParams, TEST_POLICY, mTestSessionInterface, mTestCallback); } @Test @@ -118,6 +124,7 @@ public class VerificationSessionTest { // structure is different, but all the key/value pairs should be preserved as before. assertThat(sessionFromParcel.getExtensionParams().getString(TEST_KEY)) .isEqualTo(mTestExtensionParams.getString(TEST_KEY)); + assertThat(sessionFromParcel.getVerificationPolicy()).isEqualTo(TEST_POLICY); } @Test @@ -152,4 +159,42 @@ public class VerificationSessionTest { verify(mTestCallback, times(1)).reportVerificationIncomplete( eq(TEST_ID), eq(reason)); } + + @Test + public void testPolicyNoOverride() { + assertThat(mTestSession.getVerificationPolicy()).isEqualTo(TEST_POLICY); + // This "set" is a no-op + assertThat(mTestSession.setVerificationPolicy(TEST_POLICY)).isTrue(); + assertThat(mTestSession.getVerificationPolicy()).isEqualTo(TEST_POLICY); + verifyZeroInteractions(mTestSessionInterface); + } + + @Test + public void testPolicyOverrideFail() throws Exception { + final int newPolicy = VERIFICATION_POLICY_BLOCK_FAIL_WARN; + when(mTestSessionInterface.setVerificationPolicy(anyInt(), anyInt())).thenReturn(false); + assertThat(mTestSession.setVerificationPolicy(newPolicy)).isFalse(); + verify(mTestSessionInterface, times(1)) + .setVerificationPolicy(eq(TEST_ID), eq(newPolicy)); + // Next "get" should not trigger binder call because the previous "set" has failed + assertThat(mTestSession.getVerificationPolicy()).isEqualTo(TEST_POLICY); + verifyNoMoreInteractions(mTestSessionInterface); + } + + @Test + public void testPolicyOverrideSuccess() throws Exception { + final int newPolicy = VERIFICATION_POLICY_BLOCK_FAIL_WARN; + when(mTestSessionInterface.setVerificationPolicy(anyInt(), anyInt())).thenReturn(true); + assertThat(mTestSession.setVerificationPolicy(newPolicy)).isTrue(); + verify(mTestSessionInterface, times(1)) + .setVerificationPolicy(eq(TEST_ID), eq(newPolicy)); + assertThat(mTestSession.getVerificationPolicy()).isEqualTo(newPolicy); + assertThat(mTestSession.getVerificationPolicy()).isEqualTo(newPolicy); + + // Setting back to the original policy should still trigger binder calls + assertThat(mTestSession.setVerificationPolicy(TEST_POLICY)).isTrue(); + verify(mTestSessionInterface, times(1)) + .setVerificationPolicy(eq(TEST_ID), eq(TEST_POLICY)); + assertThat(mTestSession.getVerificationPolicy()).isEqualTo(TEST_POLICY); + } } diff --git a/core/tests/coretests/src/android/content/pm/verify/VerifierServiceTest.java b/core/tests/coretests/src/android/content/pm/verify/VerifierServiceTest.java index 7f73a1eb4b48..7807c8a94530 100644 --- a/core/tests/coretests/src/android/content/pm/verify/VerifierServiceTest.java +++ b/core/tests/coretests/src/android/content/pm/verify/VerifierServiceTest.java @@ -16,6 +16,8 @@ package android.content.pm.verify; +import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_CLOSED; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.eq; @@ -52,6 +54,7 @@ public class VerifierServiceTest { private static final String TEST_PACKAGE_NAME = "com.foo"; private static final Uri TEST_PACKAGE_URI = Uri.parse("test://test"); private static final SigningInfo TEST_SIGNING_INFO = new SigningInfo(); + private static final int TEST_POLICY = VERIFICATION_POLICY_BLOCK_FAIL_CLOSED; private VerifierService mService; private VerificationSession mSession; @@ -60,8 +63,7 @@ public class VerifierServiceTest { mService = Mockito.mock(VerifierService.class, Answers.CALLS_REAL_METHODS); mSession = new VerificationSession(TEST_ID, TEST_INSTALL_SESSION_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, TEST_SIGNING_INFO, - new ArrayList<>(), - new PersistableBundle(), null, null); + new ArrayList<>(), new PersistableBundle(), TEST_POLICY, null, null); } @Test diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 2e72f0ec90b8..4aa7e96f352d 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -572,6 +572,7 @@ applications that come with the platform <permission name="android.permission.READ_BLOCKED_NUMBERS" /> <!-- Permission required for CTS test - PackageManagerTest --> <permission name="android.permission.DOMAIN_VERIFICATION_AGENT"/> + <permission name="android.permission.VERIFICATION_AGENT"/> <!-- Permission required for CTS test CtsInputTestCases --> <permission name="android.permission.OVERRIDE_SYSTEM_KEY_BEHAVIOR_IN_FOCUSED_WINDOW" /> <!-- Permission required for CTS test - PackageManagerShellCommandInstallTest --> diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 408ed1e861c3..b385aaa5c7d9 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -924,6 +924,7 @@ <!-- Permission required for CTS test - CtsPackageManagerTestCases--> <uses-permission android:name="android.permission.DOMAIN_VERIFICATION_AGENT" /> + <uses-permission android:name="android.permission.VERIFICATION_AGENT" /> <!-- Permission required for Cts test - CtsInputTestCases --> <uses-permission diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 34d939b07187..f6a808b6c33e 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -25,12 +25,14 @@ import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_NO_CONNECTIVI import static android.content.pm.PackageInstaller.UNARCHIVAL_ERROR_USER_ACTION_NEEDED; import static android.content.pm.PackageInstaller.UNARCHIVAL_GENERIC_ERROR; import static android.content.pm.PackageInstaller.UNARCHIVAL_OK; +import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_WARN; import static android.content.pm.PackageManager.DELETE_ARCHIVE; import static android.content.pm.PackageManager.INSTALL_UNARCHIVE_DRAFT; import static android.os.Process.INVALID_UID; import static android.os.Process.SYSTEM_UID; import static com.android.server.pm.PackageArchiver.isArchivingEnabled; +import static com.android.server.pm.PackageInstallerSession.isValidVerificationPolicy; import static com.android.server.pm.PackageManagerService.SHELL_PACKAGE_NAME; import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; @@ -150,6 +152,7 @@ import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.IntPredicate; import java.util.function.Supplier; @@ -275,6 +278,13 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } }; + /** + * Default verification policy for incoming installation sessions. + * TODO(b/360129657): update the default policy. + */ + private final AtomicInteger mVerificationPolicy = new AtomicInteger( + VERIFICATION_POLICY_BLOCK_FAIL_WARN); + private static final class Lifecycle extends SystemService { private final PackageInstallerService mPackageInstallerService; @@ -1042,7 +1052,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements userId, callingUid, installSource, params, createdMillis, 0L, stageDir, stageCid, null, null, false, false, false, false, null, SessionInfo.INVALID_ID, false, false, false, PackageManager.INSTALL_UNKNOWN, "", null, - mVerifierController); + mVerifierController, mVerificationPolicy.get()); synchronized (mSessions) { mSessions.put(sessionId, session); @@ -1866,6 +1876,34 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements } } + @Override + public @PackageInstaller.VerificationPolicy int getVerificationPolicy() { + if (mContext.checkCallingOrSelfPermission(Manifest.permission.VERIFICATION_AGENT) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("You need the " + + "com.android.permission.VERIFICATION_AGENT permission " + + "to get the verification policy"); + } + return mVerificationPolicy.get(); + } + + @Override + public boolean setVerificationPolicy(@PackageInstaller.VerificationPolicy int policy) { + if (mContext.checkCallingOrSelfPermission(Manifest.permission.VERIFICATION_AGENT) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("You need the " + + "com.android.permission.VERIFICATION_AGENT permission " + + "to set the verification policy"); + } + if (!isValidVerificationPolicy(policy)) { + return false; + } + if (policy != mVerificationPolicy.get()) { + mVerificationPolicy.set(policy); + } + return true; + } + private static int getSessionCount(SparseArray<PackageInstallerSession> sessions, int installerUid) { int count = 0; diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 9e0ba8492ab9..04d0d182d3b2 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -21,9 +21,17 @@ import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_INSTA import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_UPDATED_BY_DO; import static android.content.pm.DataLoaderType.INCREMENTAL; import static android.content.pm.DataLoaderType.STREAMING; +import static android.content.pm.PackageInstaller.EXTRA_VERIFICATION_FAILURE_REASON; import static android.content.pm.PackageInstaller.LOCATION_DATA_APP; import static android.content.pm.PackageInstaller.UNARCHIVAL_OK; import static android.content.pm.PackageInstaller.UNARCHIVAL_STATUS_UNSET; +import static android.content.pm.PackageInstaller.VERIFICATION_FAILED_REASON_NETWORK_UNAVAILABLE; +import static android.content.pm.PackageInstaller.VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED; +import static android.content.pm.PackageInstaller.VERIFICATION_FAILED_REASON_UNKNOWN; +import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_CLOSED; +import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_OPEN; +import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_WARN; +import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_NONE; import static android.content.pm.PackageItemInfo.MAX_SAFE_LABEL_LENGTH; import static android.content.pm.PackageManager.INSTALL_FAILED_ABORTED; import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_SIGNATURE; @@ -38,7 +46,7 @@ import static android.content.pm.PackageManager.INSTALL_FAILED_VERIFICATION_FAIL import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES; import static android.content.pm.PackageManager.INSTALL_STAGED; import static android.content.pm.PackageManager.INSTALL_SUCCEEDED; -import static android.content.pm.verify.pkg.VerificationSession.VERIFICATION_INCOMPLETE_UNKNOWN; +import static android.content.pm.verify.pkg.VerificationSession.VERIFICATION_INCOMPLETE_NETWORK_UNAVAILABLE; import static android.os.Process.INVALID_UID; import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE; import static android.system.OsConstants.O_CREAT; @@ -313,6 +321,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static final String ATTR_APPLICATION_ENABLED_SETTING_PERSISTENT = "applicationEnabledSettingPersistent"; private static final String ATTR_DOMAIN = "domain"; + private static final String ATTR_VERIFICATION_POLICY = "verificationPolicy"; private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill"; private static final int[] EMPTY_CHILD_SESSION_ARRAY = EmptyArray.INT; @@ -410,6 +419,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private final PackageSessionProvider mSessionProvider; private final SilentUpdatePolicy mSilentUpdatePolicy; /** + * The verification policy applied to this session, which might be different from the default + * verification policy used by the system. + */ + private final AtomicInteger mVerificationPolicy; + /** * Note all calls must be done outside {@link #mLock} to prevent lock inversion. */ private final StagingManager mStagingManager; @@ -791,7 +805,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (errorMsg != null) { Slog.e(TAG, "verifySession error: " + errorMsg); setSessionFailed(INSTALL_FAILED_INTERNAL_ERROR, errorMsg); - onSessionVerificationFailure(INSTALL_FAILED_INTERNAL_ERROR, errorMsg); + onSessionVerificationFailure(INSTALL_FAILED_INTERNAL_ERROR, errorMsg, + /* extras= */ null); return false; } return true; @@ -1167,7 +1182,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Nullable int[] childSessionIds, int parentSessionId, boolean isReady, boolean isFailed, boolean isApplied, int sessionErrorCode, String sessionErrorMessage, DomainSet preVerifiedDomains, - @NonNull VerifierController verifierController) { + @NonNull VerifierController verifierController, + @PackageInstaller.VerificationPolicy int verificationPolicy) { mCallback = callback; mContext = context; mPm = pm; @@ -1177,6 +1193,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { mHandler = new Handler(looper, mHandlerCallback); mStagingManager = stagingManager; mVerifierController = verifierController; + mVerificationPolicy = new AtomicInteger(verificationPolicy); this.sessionId = sessionId; this.userId = userId; @@ -2580,10 +2597,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { dispatchSessionFinished(error, detailMessage, null); } - private void onSessionVerificationFailure(int error, String msg) { + private void onSessionVerificationFailure(int error, String msg, Bundle extras) { Slog.e(TAG, "Failed to verify session " + sessionId); // Dispatch message to remove session from PackageInstallerService. - dispatchSessionFinished(error, msg, null); + dispatchSessionFinished(error, msg, extras); maybeFinishChildSessions(error, msg); } @@ -2856,7 +2873,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final String completeMsg = ExceptionUtils.getCompleteMessage(e); final String errorMsg = PackageManager.installStatusToString(e.error, completeMsg); setSessionFailed(e.error, errorMsg); - onSessionVerificationFailure(e.error, errorMsg); + onSessionVerificationFailure(e.error, errorMsg, /* extras= */ null); } if (Flags.verificationService()) { final Supplier<Computer> snapshotSupplier = mPm::snapshotComputer; @@ -2872,11 +2889,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // the installation can proceed. if (!mVerifierController.startVerificationSession(snapshotSupplier, userId, sessionId, getPackageName(), Uri.fromFile(stageDir), signingInfo, - declaredLibraries, /* extensionParams= */ null, + declaredLibraries, mVerificationPolicy.get(), /* extensionParams= */ null, new VerifierCallback(), /* retry= */ false)) { // A verifier is installed but cannot be connected. Installation disallowed. onSessionVerificationFailure(INSTALL_FAILED_INTERNAL_ERROR, - "A verifier agent is available on device but cannot be connected."); + "A verifier agent is available on device but cannot be connected.", + /* extras= */ null); } } else { // Verifier is not installed. Let the installation pass for now. @@ -2917,7 +2935,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final String completeMsg = ExceptionUtils.getCompleteMessage(e); final String errorMsg = PackageManager.installStatusToString(e.error, completeMsg); setSessionFailed(e.error, errorMsg); - onSessionVerificationFailure(e.error, errorMsg); + onSessionVerificationFailure(e.error, errorMsg, /* extras= */ null); } } @@ -2926,24 +2944,57 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { */ public class VerifierCallback { /** + * Called by the VerifierController when the verifier requests to get the current + * verification policy for this session. + */ + public @PackageInstaller.VerificationPolicy int getVerificationPolicy() { + return mVerificationPolicy.get(); + } + /** + * Called by the VerifierController when the verifier requests to change the verification + * policy for this session. + */ + public boolean setVerificationPolicy(@PackageInstaller.VerificationPolicy int policy) { + if (!isValidVerificationPolicy(policy)) { + return false; + } + mVerificationPolicy.set(policy); + return true; + } + /** * Called by the VerifierController when the connection has failed. */ public void onConnectionFailed() { - mHandler.post(() -> { - onSessionVerificationFailure(INSTALL_FAILED_VERIFICATION_FAILURE, - "A verifier agent is available on device but cannot be connected."); - }); + // TODO(b/360129657): prompt user on fail warning + handleNonPackageBlockedFailure( + /* onFailWarning= */ PackageInstallerSession.this::resumeVerify, + /* onFailClosed= */ () -> { + Bundle bundle = new Bundle(); + bundle.putInt(EXTRA_VERIFICATION_FAILURE_REASON, + VERIFICATION_FAILED_REASON_UNKNOWN); + onSessionVerificationFailure(INSTALL_FAILED_VERIFICATION_FAILURE, + "A verifier agent is available on device but cannot be connected.", + bundle); + + }); } /** * Called by the VerifierController when the verification request has timed out. */ public void onTimeout() { - mHandler.post(() -> { - mVerifierController.notifyVerificationTimeout(sessionId); - onSessionVerificationFailure(INSTALL_FAILED_VERIFICATION_FAILURE, - "Verification timed out; missing a response from the verifier within the" - + " time limit"); - }); + // Always notify the verifier, regardless of the policy. + mVerifierController.notifyVerificationTimeout(sessionId); + // TODO(b/360129657): prompt user on fail warning + handleNonPackageBlockedFailure( + /* onFailWarning= */ PackageInstallerSession.this::resumeVerify, + /* onFailClosed= */ () -> { + Bundle bundle = new Bundle(); + bundle.putInt(EXTRA_VERIFICATION_FAILURE_REASON, + VERIFICATION_FAILED_REASON_UNKNOWN); + onSessionVerificationFailure(INSTALL_FAILED_VERIFICATION_FAILURE, + "Verification timed out; missing a response from the verifier" + + " within the time limit", bundle); + }); } /** * Called by the VerifierController when the verification request has received a complete @@ -2953,17 +3004,22 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { @Nullable PersistableBundle extensionResponse) { // TODO: handle extension response mHandler.post(() -> { - if (statusReceived.isVerified()) { + if (statusReceived.isVerified() + || mVerificationPolicy.get() == VERIFICATION_POLICY_NONE) { // Continue with the rest of the verification and installation. resumeVerify(); - } else { - StringBuilder sb = new StringBuilder("Verifier rejected the installation"); - if (!TextUtils.isEmpty(statusReceived.getFailureMessage())) { - sb.append(" with message: ").append(statusReceived.getFailureMessage()); - } - onSessionVerificationFailure(INSTALL_FAILED_VERIFICATION_FAILURE, - sb.toString()); + return; + } + // Package is blocked. + StringBuilder sb = new StringBuilder("Verifier rejected the installation"); + if (!TextUtils.isEmpty(statusReceived.getFailureMessage())) { + sb.append(" with message: ").append(statusReceived.getFailureMessage()); } + Bundle bundle = new Bundle(); + bundle.putInt(EXTRA_VERIFICATION_FAILURE_REASON, + VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED); + onSessionVerificationFailure(INSTALL_FAILED_VERIFICATION_FAILURE, + sb.toString(), bundle); }); } /** @@ -2971,16 +3027,51 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { * response. */ public void onVerificationIncompleteReceived(int incompleteReason) { - mHandler.post(() -> { - if (incompleteReason == VERIFICATION_INCOMPLETE_UNKNOWN) { - // TODO: change this to a user confirmation and handle other incomplete reasons - onSessionVerificationFailure(INSTALL_FAILED_INTERNAL_ERROR, - "Verification cannot be completed for unknown reasons."); + // TODO(b/360129657): prompt user on fail warning + handleNonPackageBlockedFailure( + /* onFailWarning= */ PackageInstallerSession.this::resumeVerify, + /* onFailClosed= */ () -> { + final int failureReason; + StringBuilder sb = new StringBuilder( + "Verification cannot be completed because of "); + if (incompleteReason == VERIFICATION_INCOMPLETE_NETWORK_UNAVAILABLE) { + failureReason = VERIFICATION_FAILED_REASON_NETWORK_UNAVAILABLE; + sb.append("unavailable network."); + } else { + failureReason = VERIFICATION_FAILED_REASON_UNKNOWN; + sb.append("unknown reasons."); + } + Bundle bundle = new Bundle(); + bundle.putInt(EXTRA_VERIFICATION_FAILURE_REASON, failureReason); + onSessionVerificationFailure(INSTALL_FAILED_VERIFICATION_FAILURE, + sb.toString(), bundle); + }); + } + + private void handleNonPackageBlockedFailure(Runnable onFailWarning, Runnable onFailClosed) { + final Runnable r = switch (mVerificationPolicy.get()) { + case VERIFICATION_POLICY_NONE, VERIFICATION_POLICY_BLOCK_FAIL_OPEN -> + PackageInstallerSession.this::resumeVerify; + case VERIFICATION_POLICY_BLOCK_FAIL_WARN -> onFailWarning; + case VERIFICATION_POLICY_BLOCK_FAIL_CLOSED -> onFailClosed; + default -> { + Log.wtf(TAG, "Unknown verification policy: " + mVerificationPolicy.get()); + yield onFailClosed; } - }); + }; + mHandler.post(r); } } + /** + * Returns whether a policy is a valid verification policy. + */ + public static boolean isValidVerificationPolicy( + @PackageInstaller.VerificationPolicy int policy) { + return policy >= VERIFICATION_POLICY_NONE + && policy <= VERIFICATION_POLICY_BLOCK_FAIL_CLOSED; + } + private IntentSender getRemoteStatusReceiver() { synchronized (mLock) { return mRemoteStatusReceiver; @@ -3156,7 +3247,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (error == INSTALL_SUCCEEDED) { onVerificationComplete(); } else { - onSessionVerificationFailure(error, msg); + onSessionVerificationFailure(error, msg, /* extras= */ null); } }); }); @@ -5328,6 +5419,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } + /** + * @return the current policy for the verification request associated with this session. + */ + @VisibleForTesting + public @PackageInstaller.VerificationPolicy int getVerificationPolicy() { + assertCallerIsOwnerOrRoot(); + return mVerificationPolicy.get(); + } void setSessionReady() { synchronized (mLock) { @@ -5631,6 +5730,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (!ArrayUtils.isEmpty(warnings)) { fillIn.putStringArrayListExtra(PackageInstaller.EXTRA_WARNINGS, warnings); } + if (extras.containsKey(EXTRA_VERIFICATION_FAILURE_REASON)) { + fillIn.putExtra(EXTRA_VERIFICATION_FAILURE_REASON, + extras.getInt(EXTRA_VERIFICATION_FAILURE_REASON)); + } } try { final BroadcastOptions options = BroadcastOptions.makeBasic(); @@ -5786,6 +5889,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { out.attributeInt(null, ATTR_INSTALL_REASON, params.installReason); writeBooleanAttribute(out, ATTR_APPLICATION_ENABLED_SETTING_PERSISTENT, params.applicationEnabledSettingPersistent); + out.attributeInt(null, ATTR_VERIFICATION_POLICY, mVerificationPolicy.get()); final boolean isDataLoader = params.dataLoaderParams != null; writeBooleanAttribute(out, ATTR_IS_DATALOADER, isDataLoader); @@ -5936,6 +6040,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final boolean sealed = in.getAttributeBoolean(null, ATTR_SEALED, false); final int parentSessionId = in.getAttributeInt(null, ATTR_PARENT_SESSION_ID, SessionInfo.INVALID_ID); + final int verificationPolicy = in.getAttributeInt(null, ATTR_VERIFICATION_POLICY, + VERIFICATION_POLICY_NONE); final SessionParams params = new SessionParams( SessionParams.MODE_INVALID); @@ -6110,6 +6216,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { installerUid, installSource, params, createdMillis, committedMillis, stageDir, stageCid, fileArray, checksumsMap, prepared, committed, destroyed, sealed, childSessionIdsArray, parentSessionId, isReady, isFailed, isApplied, - sessionErrorCode, sessionErrorMessage, preVerifiedDomains, verifierController); + sessionErrorCode, sessionErrorMessage, preVerifiedDomains, verifierController, + verificationPolicy); } } diff --git a/services/core/java/com/android/server/pm/verify/pkg/VerifierController.java b/services/core/java/com/android/server/pm/verify/pkg/VerifierController.java index 7eac940933c2..b7cc7ccead89 100644 --- a/services/core/java/com/android/server/pm/verify/pkg/VerifierController.java +++ b/services/core/java/com/android/server/pm/verify/pkg/VerifierController.java @@ -30,6 +30,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInstaller; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.SharedLibraryInfo; @@ -94,9 +95,22 @@ public class VerifierController { // Max duration allowed to wait for a verifier to respond to a verification request. private static final long DEFAULT_MAX_VERIFICATION_REQUEST_EXTENDED_TIMEOUT_MILLIS = TimeUnit.MINUTES.toMillis(10); + /** + * Configurable maximum amount of time in milliseconds for the system to wait from the moment + * when the installation session requires a verification, till when the request is delivered to + * the verifier, pending the connection to be established. If the request has not been delivered + * to the verifier within this amount of time, e.g., because the verifier has crashed or ANR'd, + * the controller then sends a failure status back to the installation session. + * Flag type: {@code long} + * Namespace: NAMESPACE_PACKAGE_MANAGER_SERVICE + */ + private static final String PROPERTY_VERIFIER_CONNECTION_TIMEOUT_MILLIS = + "verifier_connection_timeout_millis"; // The maximum amount of time to wait from the moment when the session requires a verification, // till when the request is delivered to the verifier, pending the connection to be established. - private static final long CONNECTION_TIMEOUT_SECONDS = 10; + private static final long DEFAULT_VERIFIER_CONNECTION_TIMEOUT_MILLIS = + TimeUnit.SECONDS.toMillis(10); + // The maximum amount of time to wait before the system unbinds from the verifier. private static final long UNBIND_TIMEOUT_MILLIS = TimeUnit.HOURS.toMillis(6); @@ -271,6 +285,7 @@ public class VerifierController { int installationSessionId, String packageName, Uri stagedPackageUri, SigningInfo signingInfo, List<SharedLibraryInfo> declaredLibraries, + @PackageInstaller.VerificationPolicy int verificationPolicy, PersistableBundle extensionParams, PackageInstallerSession.VerifierCallback callback, boolean retry) { // Try connecting to the verifier if not already connected @@ -292,7 +307,7 @@ public class VerifierController { /* id= */ verificationId, /* installSessionId= */ installationSessionId, packageName, stagedPackageUri, signingInfo, declaredLibraries, extensionParams, - new VerificationSessionInterface(), + verificationPolicy, new VerificationSessionInterface(callback), new VerificationSessionCallback(callback)); AndroidFuture<Void> unusedFuture = mRemoteService.post(service -> { if (!retry) { @@ -306,7 +321,8 @@ public class VerifierController { } service.onVerificationRetry(session); } - }).orTimeout(CONNECTION_TIMEOUT_SECONDS, TimeUnit.SECONDS).whenComplete((res, err) -> { + }).orTimeout(mInjector.getVerifierConnectionTimeoutMillis(), TimeUnit.MILLISECONDS) + .whenComplete((res, err) -> { if (err != null) { Slog.e(TAG, "Error notifying verification request for session " + verificationId, err); @@ -407,6 +423,12 @@ public class VerifierController { // This class handles requests from the remote verifier private class VerificationSessionInterface extends IVerificationSessionInterface.Stub { + private final PackageInstallerSession.VerifierCallback mCallback; + + VerificationSessionInterface(PackageInstallerSession.VerifierCallback callback) { + mCallback = callback; + } + @Override public long getTimeoutTime(int verificationId) { checkCallerPermission(); @@ -432,6 +454,20 @@ public class VerifierController { return tracker.extendTimeRemaining(additionalMs); } } + + @Override + public boolean setVerificationPolicy(int verificationId, + @PackageInstaller.VerificationPolicy int policy) { + checkCallerPermission(); + synchronized (mVerificationStatus) { + final VerificationStatusTracker tracker = mVerificationStatus.get(verificationId); + if (tracker == null) { + throw new IllegalStateException("Verification session " + verificationId + + " doesn't exist or has finished"); + } + } + return mCallback.setVerificationPolicy(policy); + } } private class VerificationSessionCallback extends IVerificationSessionCallback.Stub { @@ -451,8 +487,8 @@ public class VerifierController { throw new IllegalStateException("Verification session " + id + " doesn't exist or has finished"); } - mCallback.onVerificationIncompleteReceived(reason); } + mCallback.onVerificationIncompleteReceived(reason); // Remove status tracking and stop the timeout countdown removeStatusTracker(id); } @@ -630,6 +666,14 @@ public class VerifierController { return getMaxVerificationExtendedTimeoutMillisFromDeviceConfig(); } + /** + * This is added so that we can mock the maximum connection timeout duration without + * calling into DeviceConfig. + */ + public long getVerifierConnectionTimeoutMillis() { + return getVerifierConnectionTimeoutMillisFromDeviceConfig(); + } + private static long getVerificationRequestTimeoutMillisFromDeviceConfig() { return DeviceConfig.getLong(NAMESPACE_PACKAGE_MANAGER_SERVICE, PROPERTY_VERIFICATION_REQUEST_TIMEOUT_MILLIS, @@ -641,5 +685,11 @@ public class VerifierController { PROPERTY_MAX_VERIFICATION_REQUEST_EXTENDED_TIMEOUT_MILLIS, DEFAULT_MAX_VERIFICATION_REQUEST_EXTENDED_TIMEOUT_MILLIS); } + + private static long getVerifierConnectionTimeoutMillisFromDeviceConfig() { + return DeviceConfig.getLong(NAMESPACE_PACKAGE_MANAGER_SERVICE, + PROPERTY_VERIFIER_CONNECTION_TIMEOUT_MILLIS, + DEFAULT_VERIFIER_CONNECTION_TIMEOUT_MILLIS); + } } } diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt index cbca434a6bb6..8af5b2081b81 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageInstallerSessionTest.kt @@ -21,6 +21,7 @@ import android.content.pm.PackageInstaller.SessionParams import android.content.pm.PackageInstaller.SessionParams.PERMISSION_STATE_DEFAULT import android.content.pm.PackageInstaller.SessionParams.PERMISSION_STATE_DENIED import android.content.pm.PackageInstaller.SessionParams.PERMISSION_STATE_GRANTED +import android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_CLOSED import android.content.pm.PackageManager import android.content.pm.verify.domain.DomainSet import android.os.Parcel @@ -33,6 +34,11 @@ import com.android.internal.os.BackgroundThread import com.android.server.pm.verify.pkg.VerifierController import com.android.server.testutils.whenever import com.google.common.truth.Truth.assertThat +import java.io.File +import java.io.FileInputStream +import java.io.FileNotFoundException +import java.io.FileOutputStream +import java.io.IOException import libcore.io.IoUtils import org.junit.Before import org.junit.Rule @@ -46,11 +52,6 @@ import org.mockito.Mockito.mock import org.mockito.MockitoAnnotations import org.xmlpull.v1.XmlPullParser import org.xmlpull.v1.XmlPullParserException -import java.io.File -import java.io.FileInputStream -import java.io.FileNotFoundException -import java.io.FileOutputStream -import java.io.IOException @Presubmit class PackageInstallerSessionTest { @@ -197,7 +198,8 @@ class PackageInstallerSessionTest { /* stagedSessionErrorCode */ PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE, /* stagedSessionErrorMessage */ "some error", /* preVerifiedDomains */ DomainSet(setOf("com.foo", "com.bar")), - /* VerifierController */ mock(VerifierController::class.java) + /* VerifierController */ mock(VerifierController::class.java), + VERIFICATION_POLICY_BLOCK_FAIL_CLOSED ) } @@ -339,6 +341,7 @@ class PackageInstallerSessionTest { assertThat(expected.childSessionIds).asList() .containsExactlyElementsIn(actual.childSessionIds.toList()) assertThat(expected.preVerifiedDomains).isEqualTo(actual.preVerifiedDomains) + assertThat(expected.verificationPolicy).isEqualTo(actual.verificationPolicy) } private fun assertInstallSourcesEquivalent(expected: InstallSource, actual: InstallSource) { diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/verify/pkg/VerifierControllerTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/verify/pkg/VerifierControllerTest.java index be094b0152bc..37b23b107ecd 100644 --- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/verify/pkg/VerifierControllerTest.java +++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/verify/pkg/VerifierControllerTest.java @@ -16,6 +16,9 @@ package com.android.server.pm.verify.pkg; +import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_CLOSED; +import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_OPEN; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -92,6 +95,9 @@ public class VerifierControllerTest { private static final long TEST_TIMEOUT_DURATION_MILLIS = TimeUnit.MINUTES.toMillis(1); private static final long TEST_MAX_TIMEOUT_DURATION_MILLIS = TimeUnit.MINUTES.toMillis(10); + private static final long TEST_VERIFIER_CONNECTION_TIMEOUT_DURATION_MILLIS = + TimeUnit.SECONDS.toMillis(10); + private static final int TEST_POLICY = VERIFICATION_POLICY_BLOCK_FAIL_CLOSED; private final ArrayList<SharedLibraryInfo> mTestDeclaredLibraries = new ArrayList<>(); private final PersistableBundle mTestExtensionParams = new PersistableBundle(); @@ -124,6 +130,9 @@ public class VerifierControllerTest { TEST_TIMEOUT_DURATION_MILLIS); when(mInjector.getMaxVerificationExtendedTimeoutMillis()).thenReturn( TEST_MAX_TIMEOUT_DURATION_MILLIS); + when(mInjector.getVerifierConnectionTimeoutMillis()).thenReturn( + TEST_VERIFIER_CONNECTION_TIMEOUT_DURATION_MILLIS + ); // Mock time forward as the code continues to check for the current time when(mInjector.getCurrentTimeMillis()) .thenReturn(TEST_REQUEST_START_TIME) @@ -159,12 +168,12 @@ public class VerifierControllerTest { .isFalse(); assertThat(mVerifierController.startVerificationSession( mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, - TEST_SIGNING_INFO, mTestDeclaredLibraries, mTestExtensionParams, mSessionCallback, - /* retry= */ false)).isFalse(); + TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams, + mSessionCallback, /* retry= */ false)).isFalse(); assertThat(mVerifierController.startVerificationSession( mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, - TEST_SIGNING_INFO, mTestDeclaredLibraries, mTestExtensionParams, mSessionCallback, - /* retry= */ true)).isFalse(); + TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams, + mSessionCallback, /* retry= */ true)).isFalse(); verifyZeroInteractions(mSessionCallback); } @@ -200,8 +209,8 @@ public class VerifierControllerTest { ServiceConnector.ServiceLifecycleCallbacks<IVerifierService> callbacks = captor.getValue(); assertThat(mVerifierController.startVerificationSession( mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, - TEST_SIGNING_INFO, mTestDeclaredLibraries, mTestExtensionParams, mSessionCallback, - /* retry= */ false)).isTrue(); + TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams, + mSessionCallback, /* retry= */ false)).isTrue(); verify(mMockService, times(1)).onVerificationRequired(any(VerificationSession.class)); callbacks.onBinderDied(); // Test that nothing crashes if the service connection is lost @@ -212,12 +221,12 @@ public class VerifierControllerTest { verifyNoMoreInteractions(mMockService); assertThat(mVerifierController.startVerificationSession( mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, - TEST_SIGNING_INFO, mTestDeclaredLibraries, mTestExtensionParams, mSessionCallback, - /* retry= */ false)).isTrue(); + TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams, + mSessionCallback, /* retry= */ false)).isTrue(); assertThat(mVerifierController.startVerificationSession( mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, - TEST_SIGNING_INFO, mTestDeclaredLibraries, mTestExtensionParams, mSessionCallback, - /* retry= */ true)).isTrue(); + TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams, + mSessionCallback, /* retry= */ true)).isTrue(); mVerifierController.notifyVerificationTimeout(TEST_ID); verify(mMockService, times(1)).onVerificationTimeout(eq(TEST_ID)); } @@ -226,8 +235,8 @@ public class VerifierControllerTest { public void testNotifyPackageNameAvailable() throws Exception { assertThat(mVerifierController.startVerificationSession( mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, - TEST_SIGNING_INFO, mTestDeclaredLibraries, mTestExtensionParams, mSessionCallback, - /* retry= */ false)).isTrue(); + TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams, + mSessionCallback, /* retry= */ false)).isTrue(); mVerifierController.notifyPackageNameAvailable(TEST_PACKAGE_NAME); verify(mMockService).onPackageNameAvailable(eq(TEST_PACKAGE_NAME)); } @@ -236,8 +245,8 @@ public class VerifierControllerTest { public void testNotifyVerificationCancelled() throws Exception { assertThat(mVerifierController.startVerificationSession( mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, - TEST_SIGNING_INFO, mTestDeclaredLibraries, mTestExtensionParams, mSessionCallback, - /* retry= */ false)).isTrue(); + TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams, + mSessionCallback, /* retry= */ false)).isTrue(); mVerifierController.notifyVerificationCancelled(TEST_PACKAGE_NAME); verify(mMockService).onVerificationCancelled(eq(TEST_PACKAGE_NAME)); } @@ -248,8 +257,8 @@ public class VerifierControllerTest { ArgumentCaptor.forClass(VerificationSession.class); assertThat(mVerifierController.startVerificationSession( mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, - TEST_SIGNING_INFO, mTestDeclaredLibraries, mTestExtensionParams, mSessionCallback, - /* retry= */ false)).isTrue(); + TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams, + mSessionCallback, /* retry= */ false)).isTrue(); verify(mMockService).onVerificationRequired(captor.capture()); VerificationSession session = captor.getValue(); assertThat(session.getId()).isEqualTo(TEST_ID); @@ -276,8 +285,8 @@ public class VerifierControllerTest { ArgumentCaptor.forClass(VerificationSession.class); assertThat(mVerifierController.startVerificationSession( mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, - TEST_SIGNING_INFO, mTestDeclaredLibraries, mTestExtensionParams, mSessionCallback, - /* retry= */ true)).isTrue(); + TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams, + mSessionCallback, /* retry= */ true)).isTrue(); verify(mMockService).onVerificationRetry(captor.capture()); VerificationSession session = captor.getValue(); assertThat(session.getId()).isEqualTo(TEST_ID); @@ -302,8 +311,8 @@ public class VerifierControllerTest { public void testNotifyVerificationTimeout() throws Exception { assertThat(mVerifierController.startVerificationSession( mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, - TEST_SIGNING_INFO, mTestDeclaredLibraries, mTestExtensionParams, mSessionCallback, - /* retry= */ true)).isTrue(); + TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams, + mSessionCallback, /* retry= */ true)).isTrue(); mVerifierController.notifyVerificationTimeout(TEST_ID); verify(mMockService).onVerificationTimeout(eq(TEST_ID)); } @@ -320,8 +329,8 @@ public class VerifierControllerTest { ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); assertThat(mVerifierController.startVerificationSession( mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, - TEST_SIGNING_INFO, mTestDeclaredLibraries, mTestExtensionParams, mSessionCallback, - /* retry= */ false)).isTrue(); + TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams, + mSessionCallback, /* retry= */ false)).isTrue(); verify(mHandler, times(1)).sendMessageAtTime(any(Message.class), anyLong()); verify(mSessionCallback, times(1)).onTimeout(); verify(mInjector, times(2)).getCurrentTimeMillis(); @@ -339,8 +348,8 @@ public class VerifierControllerTest { .thenAnswer(i -> true); assertThat(mVerifierController.startVerificationSession( mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, - TEST_SIGNING_INFO, mTestDeclaredLibraries, mTestExtensionParams, mSessionCallback, - /* retry= */ false)).isTrue(); + TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams, + mSessionCallback, /* retry= */ false)).isTrue(); verify(mHandler, times(1)).sendMessageAtTime(any(Message.class), anyLong()); verify(mSessionCallback, times(1)).onTimeout(); verify(mInjector, times(2)).getCurrentTimeMillis(); @@ -350,8 +359,8 @@ public class VerifierControllerTest { ArgumentCaptor.forClass(VerificationSession.class); assertThat(mVerifierController.startVerificationSession( mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, - TEST_SIGNING_INFO, mTestDeclaredLibraries, mTestExtensionParams, mSessionCallback, - /* retry= */ true)).isTrue(); + TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams, + mSessionCallback, /* retry= */ true)).isTrue(); verify(mMockService).onVerificationRetry(captor.capture()); VerificationSession session = captor.getValue(); VerificationStatus status = new VerificationStatus.Builder().setVerified(true).build(); @@ -367,8 +376,8 @@ public class VerifierControllerTest { ArgumentCaptor.forClass(VerificationSession.class); assertThat(mVerifierController.startVerificationSession( mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, - TEST_SIGNING_INFO, mTestDeclaredLibraries, mTestExtensionParams, mSessionCallback, - /* retry= */ false)).isTrue(); + TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams, + mSessionCallback, /* retry= */ false)).isTrue(); verify(mMockService).onVerificationRequired(captor.capture()); VerificationSession session = captor.getValue(); session.reportVerificationIncomplete(VerificationSession.VERIFICATION_INCOMPLETE_UNKNOWN); @@ -383,8 +392,8 @@ public class VerifierControllerTest { ArgumentCaptor.forClass(VerificationSession.class); assertThat(mVerifierController.startVerificationSession( mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, - TEST_SIGNING_INFO, mTestDeclaredLibraries, mTestExtensionParams, mSessionCallback, - /* retry= */ false)).isTrue(); + TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams, + mSessionCallback, /* retry= */ false)).isTrue(); verify(mMockService).onVerificationRequired(captor.capture()); VerificationSession session = captor.getValue(); VerificationStatus status = new VerificationStatus.Builder().setVerified(true).build(); @@ -401,8 +410,8 @@ public class VerifierControllerTest { ArgumentCaptor.forClass(VerificationSession.class); assertThat(mVerifierController.startVerificationSession( mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, - TEST_SIGNING_INFO, mTestDeclaredLibraries, mTestExtensionParams, mSessionCallback, - /* retry= */ false)).isTrue(); + TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams, + mSessionCallback, /* retry= */ false)).isTrue(); verify(mMockService).onVerificationRequired(captor.capture()); VerificationSession session = captor.getValue(); VerificationStatus status = new VerificationStatus.Builder() @@ -421,8 +430,8 @@ public class VerifierControllerTest { ArgumentCaptor.forClass(VerificationSession.class); assertThat(mVerifierController.startVerificationSession( mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, - TEST_SIGNING_INFO, mTestDeclaredLibraries, mTestExtensionParams, mSessionCallback, - /* retry= */ false)).isTrue(); + TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams, + mSessionCallback, /* retry= */ false)).isTrue(); verify(mMockService).onVerificationRequired(captor.capture()); VerificationSession session = captor.getValue(); VerificationStatus status = new VerificationStatus.Builder().setVerified(true).build(); @@ -439,8 +448,8 @@ public class VerifierControllerTest { ArgumentCaptor.forClass(VerificationSession.class); mVerifierController.startVerificationSession( mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, - TEST_SIGNING_INFO, mTestDeclaredLibraries, mTestExtensionParams, mSessionCallback, - /* retry= */ false); + TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams, + mSessionCallback, /* retry= */ false); verify(mMockService).onVerificationRequired(captor.capture()); VerificationSession session = captor.getValue(); final long initialTimeoutTime = TEST_REQUEST_START_TIME + TEST_TIMEOUT_DURATION_MILLIS; @@ -456,8 +465,8 @@ public class VerifierControllerTest { ArgumentCaptor.forClass(VerificationSession.class); mVerifierController.startVerificationSession( mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, - TEST_SIGNING_INFO, mTestDeclaredLibraries, mTestExtensionParams, mSessionCallback, - /* retry= */ false); + TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams, + mSessionCallback, /* retry= */ false); verify(mMockService).onVerificationRequired(captor.capture()); VerificationSession session = captor.getValue(); final long initialTimeoutTime = TEST_REQUEST_START_TIME + TEST_TIMEOUT_DURATION_MILLIS; @@ -493,10 +502,27 @@ public class VerifierControllerTest { .thenReturn(TEST_REQUEST_START_TIME + TEST_TIMEOUT_DURATION_MILLIS + 1); mVerifierController.startVerificationSession( mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, - TEST_SIGNING_INFO, mTestDeclaredLibraries, mTestExtensionParams, mSessionCallback, - /* retry= */ false); + TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams, + mSessionCallback, /* retry= */ false); verify(mHandler, times(3)).sendMessageAtTime(any(Message.class), anyLong()); verify(mInjector, times(6)).getCurrentTimeMillis(); verify(mSessionCallback, times(1)).onTimeout(); } + + @Test + public void testPolicyOverride() throws Exception { + ArgumentCaptor<VerificationSession> captor = + ArgumentCaptor.forClass(VerificationSession.class); + mVerifierController.startVerificationSession( + mSnapshotSupplier, 0, TEST_ID, TEST_PACKAGE_NAME, TEST_PACKAGE_URI, + TEST_SIGNING_INFO, mTestDeclaredLibraries, TEST_POLICY, mTestExtensionParams, + mSessionCallback, /* retry= */ false); + verify(mMockService).onVerificationRequired(captor.capture()); + VerificationSession session = captor.getValue(); + final int policy = VERIFICATION_POLICY_BLOCK_FAIL_OPEN; + when(mSessionCallback.setVerificationPolicy(eq(policy))).thenReturn(true); + assertThat(session.setVerificationPolicy(policy)).isTrue(); + assertThat(session.getVerificationPolicy()).isEqualTo(policy); + verify(mSessionCallback, times(1)).setVerificationPolicy(eq(policy)); + } } diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java index 43a8aa957fa5..124c41ed449f 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/StagingManagerTest.java @@ -741,7 +741,8 @@ public class StagingManagerTest { /* stagedSessionErrorCode */ PackageManager.INSTALL_UNKNOWN, /* stagedSessionErrorMessage */ "no error", /* preVerifiedDomains */ null, - /* verifierController */ null); + /* verifierController */ null, + /* verificationPolicy */ PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_CLOSED); StagingManager.StagedSession stagedSession = spy(session.mStagedSession); doReturn(packageName).when(stagedSession).getPackageName(); |