[4/N] APIs for verification policy and failure reasons
+ Define failure reason codes
+ Define policy constants
+ Removed VERIFICATION_FAILED_REASON_NETWORK_LIMITED
+ Add getter/setter for session and global policy overrides
+ Allow Shell to have VERIFICATION_AGENT permission
FLAG: android.content.pm.verification_service
BUG: 360129103
BUG: 360129657
Test: atest CtsPackageManagerTestCases:VerifierServiceTest
Change-Id: Ibfeb88ad71677c4c61476c8af6b8607c131072f6
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index fa4fc43..349d06c 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -4170,9 +4170,11 @@
}
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 @@
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 @@
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 451c0e5..c911326 100644
--- a/core/java/android/content/pm/IPackageInstaller.aidl
+++ b/core/java/android/content/pm/IPackageInstaller.aidl
@@ -93,4 +93,10 @@
@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 c673d58..cba7bc9 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.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 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 @@
@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 @@
}
/**
+ * 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 7a9484a..036c1e6 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 @@
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 70b4a02..f393be8 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.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 @@
* 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 @@
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 @@
@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 @@
mSigningInfo = signingInfo;
mDeclaredLibraries = declaredLibraries;
mExtensionParams = extensionParams;
+ mVerificationPolicy = defaultPolicy;
mSession = session;
mCallback = callback;
}
@@ -144,7 +151,7 @@
/**
* 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 @@
}
/**
+ * 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 @@
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 @@
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 987f68d..80255c5 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.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 @@
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 @@
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 @@
// 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 @@
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 7f73a1e..7807c8a 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 @@
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 @@
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 2e72f0e..4aa7e96 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -572,6 +572,7 @@
<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 408ed1e..b385aaa 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 34d939b..f6a808b 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_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.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 @@
}
};
+ /**
+ * 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 @@
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 @@
}
}
+ @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 9e0ba84..04d0d18 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_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_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 @@
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 @@
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 @@
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 @@
@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 @@
mHandler = new Handler(looper, mHandlerCallback);
mStagingManager = stagingManager;
mVerifierController = verifierController;
+ mVerificationPolicy = new AtomicInteger(verificationPolicy);
this.sessionId = sessionId;
this.userId = userId;
@@ -2580,10 +2597,10 @@
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 @@
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 @@
// 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 @@
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 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 @@
@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,14 +3027,49 @@
* 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() {
@@ -3156,7 +3247,7 @@
if (error == INSTALL_SUCCEEDED) {
onVerificationComplete();
} else {
- onSessionVerificationFailure(error, msg);
+ onSessionVerificationFailure(error, msg, /* extras= */ null);
}
});
});
@@ -5328,6 +5419,14 @@
}
}
+ /**
+ * @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 @@
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 @@
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 @@
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 @@
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 7eac940..b7cc7cce 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.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 @@
// 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 @@
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 @@
/* 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 @@
}
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 @@
// 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 @@
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 @@
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 @@
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 @@
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 cbca434..8af5b20 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.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.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.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 @@
/* 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 @@
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 be094b0..37b23b1 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 @@
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 @@
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 @@
.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 @@
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 @@
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 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 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 @@
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 @@
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 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 @@
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 @@
.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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
.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 43a8aa9..124c41e 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 @@
/* 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();