Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2dde455f authored by Song Chun Fan's avatar Song Chun Fan
Browse files

[ADI][18/N] Add VERIFICATION_USER_ACTION_NEEDED_REASON constants

Previously, the verification failure reason code constants are used in
both the result sent to the installer, as well as the user confirmation
dialogs. This caused confusion and made it difficult to extend the user
confirmation reasons without adding failure reasons. This CL decouples the
two types of reasons, and clarifies their usages in the javadocs.

+ Update javadoc to reflect the different behaviors of installers based
  on their target SDK and privileged status

+ Add constants for verification user action reasons which are now separated
  from the verification failure reasons. The user action reasons will be
exclusively used in the user confirmation dialogs, wherease the
verification failure reasons are used to inform the installer.

+ Refactor the code a bit to make it more concise.

+ Update the value of the failure reason extra in a couple of places to match
  the expected behavior described in the javadoc.

FLAG: android.content.pm.verification_service
BUG: 360129657
Test: cts tests to be added
API-Coverage-Bug: 367776952

Merged-In: I34f8672453e07fdb7b448d6ac44a807fcceca0d6
Change-Id: I34f8672453e07fdb7b448d6ac44a807fcceca0d6
parent 9ab3384c
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -4378,10 +4378,13 @@ package android.content.pm {
    ctor public PackageInstaller.VerificationUserConfirmationInfo();
    ctor public PackageInstaller.VerificationUserConfirmationInfo(int, int);
    method public int describeContents();
    method public int getVerificationFailureReason();
    method public int getVerificationPolicy();
    method public int getVerificationUserActionNeededReason();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.VerificationUserConfirmationInfo> CREATOR;
    field public static final int VERIFICATION_USER_ACTION_NEEDED_REASON_NETWORK_UNAVAILABLE = 1; // 0x1
    field public static final int VERIFICATION_USER_ACTION_NEEDED_REASON_PACKAGE_BLOCKED = 2; // 0x2
    field public static final int VERIFICATION_USER_ACTION_NEEDED_REASON_UNKNOWN = 0; // 0x0
  }
  public class PackageItemInfo {
+78 −20
Original line number Diff line number Diff line
@@ -443,12 +443,36 @@ 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
     * When an installation fails because the verification was incomplete or blocked,
     * this extra provides a code that explains the reason, such
     * as {@link #VERIFICATION_FAILED_REASON_NETWORK_UNAVAILABLE}. It is included in 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.
     * {@link Session#commit(IntentSender)}. However, along with this reason code, installers can
     * receive different status codes from {@link #EXTRA_STATUS} depending on their target SDK and
     * privileged status:
     * <p>
     *      Non-privileged installers targeting 36 or less will first receive the
     *      {@link #STATUS_PENDING_USER_ACTION} status code without this reason code. They will be
     *      forced through the user action flow to allow the OS to inform the user of such
     *      verification context before continuing to fail the install. If the user has the option
     *      to bypass the verification result and chooses to do so, the installation will proceed.
     *      Otherwise, the installer will receive the {@link #STATUS_FAILURE_ABORTED} status code
     *      along with this reason code that explains why the verification had failed.
     * </p>
     * <p>
     *     Privileged installer targeting 36 or less will directly receive the
     *     {@link #STATUS_FAILURE_ABORTED} status code. This is because they are not expected to
     *     have the capability of handling the {@link #STATUS_PENDING_USER_ACTION} flow, so the
     *     installation will directly fail. This reason code will be supplied to them for
     *     providing additional information.
     * </p>
     * <p>
     *     All installers targeting 37 and higher will receive a {@link #STATUS_FAILURE_ABORTED}
     *     status code along with this reason code, so the installers can explain the failure to the
     *     user accordingly. An {@link Intent#EXTRA_INTENT} will also be populated with an intent
     *     that can provide additional context where appropriate, should the installer prefer to
     *     defer to the OS to explain the failure to the user.
     * </p>
     */
    @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE)
    public static final String EXTRA_VERIFICATION_FAILURE_REASON =
@@ -850,22 +874,29 @@ public class PackageInstaller {
    @SystemApi
    public static final int VERIFICATION_POLICY_NONE = 0; // platform default
    /**
     * Only block installations on {@link #VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED}.
     * Only block installations when the verification status says the package is blocked,
     * and ask the user if they'd like to install anyway when the verification cannot complete for
     * any other reason. In case of a network issue, the user also has the option to retry the
     * verification.
     * @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.
     * Only block installations when the verification result says the package is blocked,
     * and ask the user if they'd like to install anyway when the verification cannot complete for
     * any other reason. In case of a network issue, the user also has the option to retry the
     * verification.
     * @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.
     * Block installations when the verification result says the package is blocked or when the
     * verification cannot be conducted because of unknown reasons. In case of a network issue,
     * the user has the option to retry the verification.
     * @hide
     */
    @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE)
@@ -4981,32 +5012,59 @@ public class PackageInstaller {
    }

    /**
     * Details about an incomplete or failed verification.
     * Details about an incomplete or failed verification that requires user intervention.
     *
     * @hide
     */
    @FlaggedApi(Flags.FLAG_VERIFICATION_SERVICE)
    @SystemApi
    public static final class VerificationUserConfirmationInfo implements Parcelable {
        /**
         * Verification requires user intervention because of unknown reasons, such as when the
         * verifier times out or cannot be connected.
         */
        public static final int VERIFICATION_USER_ACTION_NEEDED_REASON_UNKNOWN = 0;

        /**
         * Verification requires user intervention because the network is unavailable.
         */
        public static final int VERIFICATION_USER_ACTION_NEEDED_REASON_NETWORK_UNAVAILABLE = 1;

        /**
         * Verification requires user intervention because the package is blocked.
         */
        public static final int VERIFICATION_USER_ACTION_NEEDED_REASON_PACKAGE_BLOCKED = 2;

        /**
         * @hide
         */
        @IntDef(value = {
                VERIFICATION_USER_ACTION_NEEDED_REASON_UNKNOWN,
                VERIFICATION_USER_ACTION_NEEDED_REASON_NETWORK_UNAVAILABLE,
                VERIFICATION_USER_ACTION_NEEDED_REASON_PACKAGE_BLOCKED,
        })
        @Retention(RetentionPolicy.SOURCE)
        public @interface UserActionNeededReason {
        }

        @VerificationPolicy
        private int mVerificationPolicy;

        @VerificationFailedReason
        private int mVerificationFailureReason;
        @UserActionNeededReason
        private int mVerificationUserActionNeededReason;

        public VerificationUserConfirmationInfo() {
        }

        public VerificationUserConfirmationInfo(@VerificationPolicy int policy,
                @VerificationFailedReason int failureReason) {
                @UserActionNeededReason int reason) {
            mVerificationPolicy = policy;
            mVerificationFailureReason = failureReason;
            mVerificationUserActionNeededReason = reason;
        }

        private VerificationUserConfirmationInfo(@NonNull Parcel in) {
            mVerificationPolicy = in.readInt();
            mVerificationFailureReason = in.readInt();
            mVerificationUserActionNeededReason = in.readInt();
        }

        @VerificationPolicy
@@ -5014,9 +5072,9 @@ public class PackageInstaller {
            return mVerificationPolicy;
        }

        @VerificationFailedReason
        public int getVerificationFailureReason() {
            return mVerificationFailureReason;
        @UserActionNeededReason
        public int getVerificationUserActionNeededReason() {
            return mVerificationUserActionNeededReason;
        }

        @Override
@@ -5027,7 +5085,7 @@ public class PackageInstaller {
        @Override
        public void writeToParcel(@NonNull Parcel dest, int flags) {
            dest.writeInt(mVerificationPolicy);
            dest.writeInt(mVerificationFailureReason);
            dest.writeInt(mVerificationUserActionNeededReason);
        }

        public static final @NonNull Parcelable.Creator<VerificationUserConfirmationInfo>
@@ -5047,7 +5105,7 @@ public class PackageInstaller {
        public String toString() {
            return "VerificationUserConfirmationInfo{"
                    + "verificationPolicy=" + mVerificationPolicy
                    + ", vericationFailureReason=" + mVerificationFailureReason
                    + ", verificationUserActionReason=" + mVerificationUserActionNeededReason
                    + '}';
        }
    }
+19 −17
Original line number Diff line number Diff line
@@ -19,9 +19,6 @@ package com.android.packageinstaller;
import static android.content.pm.PackageInstaller.EXTRA_SESSION_ID;
import static android.content.pm.PackageInstaller.SessionInfo;
import static android.content.pm.PackageInstaller.SessionInfo.INVALID_ID;
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_OPEN;
import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_WARN;
import static android.content.pm.PackageInstaller.VERIFICATION_USER_RESPONSE_CANCEL;
@@ -29,6 +26,9 @@ import static android.content.pm.PackageInstaller.VERIFICATION_USER_RESPONSE_ERR
import static android.content.pm.PackageInstaller.VERIFICATION_USER_RESPONSE_INSTALL_ANYWAY;
import static android.content.pm.PackageInstaller.VERIFICATION_USER_RESPONSE_OK;
import static android.content.pm.PackageInstaller.VERIFICATION_USER_RESPONSE_RETRY;
import static android.content.pm.PackageInstaller.VerificationUserConfirmationInfo.VERIFICATION_USER_ACTION_NEEDED_REASON_NETWORK_UNAVAILABLE;
import static android.content.pm.PackageInstaller.VerificationUserConfirmationInfo.VERIFICATION_USER_ACTION_NEEDED_REASON_PACKAGE_BLOCKED;
import static android.content.pm.PackageInstaller.VerificationUserConfirmationInfo.VERIFICATION_USER_ACTION_NEEDED_REASON_UNKNOWN;

import static com.android.packageinstaller.PackageUtil.AppSnippet;

@@ -111,8 +111,8 @@ public class ConfirmVerification extends Activity {
        }

        int dialogTypeFlag = getUserConfirmationDialogFlag(verificationInfo);
        int failureReason = verificationInfo.getVerificationFailureReason();
        int msgResId = getDialogMessageResourceId(failureReason);
        int userActionNeededReason = verificationInfo.getVerificationUserActionNeededReason();
        int msgResId = getDialogMessageResourceId(userActionNeededReason);

        AlertDialog.Builder builder = new AlertDialog.Builder(this)
                .setIcon(mAppSnippet.icon)
@@ -160,7 +160,8 @@ public class ConfirmVerification extends Activity {
        } else {
            // allow only acknowledging the error
            builder.setPositiveButton(
                    (failureReason == VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED)
                    (userActionNeededReason
                            == VERIFICATION_USER_ACTION_NEEDED_REASON_PACKAGE_BLOCKED)
                            ? R.string.close
                            : R.string.ok,
                    (dialog, which) -> {
@@ -203,17 +204,18 @@ public class ConfirmVerification extends Activity {
    }

    /**
     * Returns the correct type of dialog based on the verification policy and the failure reason
     * Returns the correct type of dialog based on the verification policy and the reason for user
     * action.
     */
    public static int getUserConfirmationDialogFlag(
            VerificationUserConfirmationInfo verificationInfo) {
        int verificationFailureReason = verificationInfo.getVerificationFailureReason();
        int userActionNeededReason = verificationInfo.getVerificationUserActionNeededReason();
        int verificationPolicy = verificationInfo.getVerificationPolicy();

        return switch (verificationFailureReason) {
            case VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED -> 0;
        return switch (userActionNeededReason) {
            case VERIFICATION_USER_ACTION_NEEDED_REASON_PACKAGE_BLOCKED -> 0;

            case VERIFICATION_FAILED_REASON_NETWORK_UNAVAILABLE -> {
            case VERIFICATION_USER_ACTION_NEEDED_REASON_NETWORK_UNAVAILABLE -> {
                int flag = FLAG_VERIFICATION_FAILED_MAY_RETRY;
                if (verificationPolicy == VERIFICATION_POLICY_BLOCK_FAIL_OPEN
                        || verificationPolicy == VERIFICATION_POLICY_BLOCK_FAIL_WARN) {
@@ -222,7 +224,7 @@ public class ConfirmVerification extends Activity {
                yield flag;
            }

            case VERIFICATION_FAILED_REASON_UNKNOWN -> {
            case VERIFICATION_USER_ACTION_NEEDED_REASON_UNKNOWN -> {
                int flag = 0;
                if (verificationPolicy == VERIFICATION_POLICY_BLOCK_FAIL_OPEN
                        || verificationPolicy == VERIFICATION_POLICY_BLOCK_FAIL_WARN) {
@@ -232,18 +234,18 @@ public class ConfirmVerification extends Activity {
            }

            default -> {
                Log.e(TAG, "Unknown failure reason: " + verificationFailureReason);
                Log.e(TAG, "Unknown user action needed reason: " + userActionNeededReason);
                yield 0;
            }
        };
    }

    private int getDialogMessageResourceId(int failureReason) {
        return switch (failureReason) {
            case VERIFICATION_FAILED_REASON_UNKNOWN ->
    private int getDialogMessageResourceId(int userActionNeededReason) {
        return switch (userActionNeededReason) {
            case VERIFICATION_USER_ACTION_NEEDED_REASON_UNKNOWN ->
                    R.string.cannot_install_verification_unavailable_summary;

            case VERIFICATION_FAILED_REASON_NETWORK_UNAVAILABLE ->
            case VERIFICATION_USER_ACTION_NEEDED_REASON_NETWORK_UNAVAILABLE ->
                    R.string.verification_incomplete_summary;

            default -> R.string.cannot_install_package_summary;
+20 −18
Original line number Diff line number Diff line
@@ -16,15 +16,15 @@

package com.android.packageinstaller.v2.ui.fragments;

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_OPEN;
import static android.content.pm.PackageInstaller.VERIFICATION_POLICY_BLOCK_FAIL_WARN;
import static android.content.pm.PackageInstaller.VERIFICATION_USER_RESPONSE_CANCEL;
import static android.content.pm.PackageInstaller.VERIFICATION_USER_RESPONSE_INSTALL_ANYWAY;
import static android.content.pm.PackageInstaller.VERIFICATION_USER_RESPONSE_OK;
import static android.content.pm.PackageInstaller.VERIFICATION_USER_RESPONSE_RETRY;
import static android.content.pm.PackageInstaller.VerificationUserConfirmationInfo.VERIFICATION_USER_ACTION_NEEDED_REASON_NETWORK_UNAVAILABLE;
import static android.content.pm.PackageInstaller.VerificationUserConfirmationInfo.VERIFICATION_USER_ACTION_NEEDED_REASON_PACKAGE_BLOCKED;
import static android.content.pm.PackageInstaller.VerificationUserConfirmationInfo.VERIFICATION_USER_ACTION_NEEDED_REASON_UNKNOWN;

import static com.android.packageinstaller.ConfirmVerification.FLAG_VERIFICATION_FAILED_MAY_BYPASS;
import static com.android.packageinstaller.ConfirmVerification.FLAG_VERIFICATION_FAILED_MAY_RETRY;
@@ -78,8 +78,8 @@ public class VerificationConfirmationFragment extends DialogFragment {
        VerificationUserConfirmationInfo verificationInfo = mDialogData.getVerificationInfo();
        assert verificationInfo != null;
        int dialogTypeFlag = getUserConfirmationDialogFlag(verificationInfo);
        int failureReason = verificationInfo.getVerificationFailureReason();
        int msgResId = getDialogMessageResourceId(failureReason);
        int userActionNeededReasonReason = verificationInfo.getVerificationUserActionNeededReason();
        int msgResId = getDialogMessageResourceId(userActionNeededReasonReason);

        AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity())
                .setIcon(mDialogData.getAppIcon())
@@ -117,8 +117,9 @@ public class VerificationConfirmationFragment extends DialogFragment {
        } else {
            // allow only acknowledging the error
            builder.setPositiveButton(
                    (failureReason == VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED) ? R.string.close
                            : R.string.ok,
                    (userActionNeededReasonReason
                            == VERIFICATION_USER_ACTION_NEEDED_REASON_PACKAGE_BLOCKED)
                            ? R.string.close : R.string.ok,
                    (dialog, which) -> mInstallActionListener.setVerificationUserResponse(
                            VERIFICATION_USER_RESPONSE_OK));
        }
@@ -163,17 +164,18 @@ public class VerificationConfirmationFragment extends DialogFragment {
    }

    /**
     * Returns the correct type of dialog based on the verification policy and the failure reason
     * Returns the correct type of dialog based on the verification policy and the reason for user
     * action
     */
    private int getUserConfirmationDialogFlag(
            VerificationUserConfirmationInfo verificationInfo) {
        int verificationFailureReason = verificationInfo.getVerificationFailureReason();
        int userActionNeededReason = verificationInfo.getVerificationUserActionNeededReason();
        int verificationPolicy = verificationInfo.getVerificationPolicy();

        return switch (verificationFailureReason) {
            case VERIFICATION_FAILED_REASON_PACKAGE_BLOCKED -> 0;
        return switch (userActionNeededReason) {
            case VERIFICATION_USER_ACTION_NEEDED_REASON_PACKAGE_BLOCKED -> 0;

            case VERIFICATION_FAILED_REASON_NETWORK_UNAVAILABLE -> {
            case VERIFICATION_USER_ACTION_NEEDED_REASON_NETWORK_UNAVAILABLE -> {
                int flag = FLAG_VERIFICATION_FAILED_MAY_RETRY;
                if (verificationPolicy == VERIFICATION_POLICY_BLOCK_FAIL_OPEN
                        || verificationPolicy == VERIFICATION_POLICY_BLOCK_FAIL_WARN) {
@@ -182,7 +184,7 @@ public class VerificationConfirmationFragment extends DialogFragment {
                yield flag;
            }

            case VERIFICATION_FAILED_REASON_UNKNOWN -> {
            case VERIFICATION_USER_ACTION_NEEDED_REASON_UNKNOWN -> {
                int flag = 0;
                if (verificationPolicy == VERIFICATION_POLICY_BLOCK_FAIL_OPEN
                        || verificationPolicy == VERIFICATION_POLICY_BLOCK_FAIL_WARN) {
@@ -192,18 +194,18 @@ public class VerificationConfirmationFragment extends DialogFragment {
            }

            default -> {
                Log.e(LOG_TAG, "Unknown failure reason: " + verificationFailureReason);
                Log.e(LOG_TAG, "Unknown user action needed reason: " + userActionNeededReason);
                yield 0;
            }
        };
    }

    private int getDialogMessageResourceId(int failureReason) {
        return switch (failureReason) {
            case VERIFICATION_FAILED_REASON_UNKNOWN ->
    private int getDialogMessageResourceId(int userActionNeededReason) {
        return switch (userActionNeededReason) {
            case VERIFICATION_USER_ACTION_NEEDED_REASON_UNKNOWN ->
                    R.string.cannot_install_verification_unavailable_summary;

            case VERIFICATION_FAILED_REASON_NETWORK_UNAVAILABLE ->
            case VERIFICATION_USER_ACTION_NEEDED_REASON_NETWORK_UNAVAILABLE ->
                    R.string.verification_incomplete_summary;

            default -> R.string.cannot_install_package_summary;
+75 −80

File changed.

Preview size limit exceeded, changes collapsed.