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

Commit 8c85b277 authored by Song Chun Fan's avatar Song Chun Fan
Browse files

[ADI][48/N] remove dialog from Pia V1

There is no verification dialogs designed for V1 and the feature isn't
backward compatible with devices of older releases. There's no need to
maintain the developer verification dialog in Pia V1.

BUG: 360129657
FLAG: android.content.pm.verification_service
Test: builds

Change-Id: I40dda3eb0e66f3639ea44603d32dd5f9d8967f21
parent c837a52a
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -89,9 +89,6 @@
                android:exported="false"
                android:enableOnBackInvokedCallback="false" />

        <activity android:name=".ConfirmDeveloperVerification"
            android:exported="false" />

        <activity android:name=".InstallInstalling"
                android:exported="false"
                android:enableOnBackInvokedCallback="false" />
+0 −245
Original line number Diff line number Diff line
/*
 * Copyright 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.packageinstaller;

import static android.content.pm.PackageInstaller.DEVELOPER_VERIFICATION_POLICY_BLOCK_FAIL_CLOSED;
import static android.content.pm.PackageInstaller.DEVELOPER_VERIFICATION_USER_RESPONSE_ABORT;
import static android.content.pm.PackageInstaller.DEVELOPER_VERIFICATION_USER_RESPONSE_ERROR;
import static android.content.pm.PackageInstaller.DEVELOPER_VERIFICATION_USER_RESPONSE_INSTALL_ANYWAY;
import static android.content.pm.PackageInstaller.DeveloperVerificationUserConfirmationInfo.DEVELOPER_VERIFICATION_USER_ACTION_NEEDED_REASON_DEVELOPER_BLOCKED;
import static android.content.pm.PackageInstaller.DeveloperVerificationUserConfirmationInfo.DEVELOPER_VERIFICATION_USER_ACTION_NEEDED_REASON_LITE_VERIFICATION;
import static android.content.pm.PackageInstaller.DeveloperVerificationUserConfirmationInfo.DEVELOPER_VERIFICATION_USER_ACTION_NEEDED_REASON_NETWORK_UNAVAILABLE;
import static android.content.pm.PackageInstaller.DeveloperVerificationUserConfirmationInfo.DEVELOPER_VERIFICATION_USER_ACTION_NEEDED_REASON_UNKNOWN;
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 com.android.packageinstaller.PackageUtil.AppSnippet;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.DeveloperVerificationUserConfirmationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.io.File;

public class ConfirmDeveloperVerification extends Activity {

    private static final String TAG = ConfirmDeveloperVerification.class.getSimpleName();

    private final boolean mLocalLOGV = false;
    private PackageManager mPackageManager;
    private PackageInstaller mPackageInstaller;
    private AlertDialog mDialog;
    private AppSnippet mAppSnippet;
    private Button mPositiveBtn;
    private Button mNegativeBtn;
    private Button mNeutralBtn;

    @Override
    @SuppressLint("MissingPermission")
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mPackageManager = getPackageManager();
        mPackageInstaller = mPackageManager.getPackageInstaller();

        Intent intent = getIntent();
        int sessionId = intent.getIntExtra(EXTRA_SESSION_ID, INVALID_ID);

        SessionInfo sessionInfo = mPackageInstaller.getSessionInfo(sessionId);
        String resolvedPath = sessionInfo != null ? sessionInfo.getResolvedBaseApkPath() : null;
        if (sessionInfo == null || !sessionInfo.isSealed() || resolvedPath == null) {
            Log.e(TAG, "Session " + sessionId + " in funky state; ignoring");
            mPackageInstaller.setDeveloperVerificationUserResponse(sessionId,
                    DEVELOPER_VERIFICATION_USER_RESPONSE_ERROR);
            finish();
            return;
        }

        DeveloperVerificationUserConfirmationInfo verificationInfo =
                mPackageInstaller.getDeveloperVerificationUserConfirmationInfo(sessionId);
        if (verificationInfo == null) {
            Log.e(TAG, "Could not get VerificationInfo for sessionId " + sessionId);
            mPackageInstaller.setDeveloperVerificationUserResponse(sessionId,
                    DEVELOPER_VERIFICATION_USER_RESPONSE_ERROR);
            finish();
            return;
        }

        mAppSnippet = generateAppSnippet(resolvedPath);
        if (mAppSnippet == null) {
            Log.e(TAG, "Could not generate AppSnippet for session " + sessionId);
            if (mLocalLOGV) {
                Log.d(TAG, "Failed to generate AppSnippet for path " + resolvedPath);
            }
            mPackageInstaller.setDeveloperVerificationUserResponse(sessionId,
                    DEVELOPER_VERIFICATION_USER_RESPONSE_ERROR);
            finish();
            return;
        }

        boolean isBypassAllowed = isBypassAllowed(verificationInfo);
        int userActionNeededReason = verificationInfo.getUserActionNeededReason();
        int msgResId = getDialogMessageResourceId(userActionNeededReason);

        AlertDialog.Builder builder = new AlertDialog.Builder(this)
                .setIcon(mAppSnippet.icon)
                .setTitle(mAppSnippet.label)
                .setMessage(msgResId);


        if (isBypassAllowed) {
            // allow bypass
            builder.setPositiveButton(R.string.dont_install, (dialog, which) -> {
                mPackageInstaller.setDeveloperVerificationUserResponse(sessionId,
                        DEVELOPER_VERIFICATION_USER_RESPONSE_ABORT);
                finish();
            }).setNegativeButton(R.string.install_anyway, (dialog, which) -> {
                mPackageInstaller.setDeveloperVerificationUserResponse(sessionId,
                        DEVELOPER_VERIFICATION_USER_RESPONSE_INSTALL_ANYWAY);
                finish();
            });
        } else {
            // allow only acknowledging the error
            builder.setPositiveButton(
                    (userActionNeededReason
                            == DEVELOPER_VERIFICATION_USER_ACTION_NEEDED_REASON_DEVELOPER_BLOCKED)
                            ? R.string.close
                            : R.string.ok,
                    (dialog, which) -> {
                        mPackageInstaller.setDeveloperVerificationUserResponse(sessionId,
                                PackageInstaller.DEVELOPER_VERIFICATION_USER_RESPONSE_ABORT);
                        finish();
                    });
        }

        mDialog = builder.create();
        mPositiveBtn = mDialog.getButton(DialogInterface.BUTTON_POSITIVE);
        mNegativeBtn = mDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
        mNeutralBtn = mDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
        mDialog.show();

        mDialog.setOnCancelListener(dialog -> {
            mPackageInstaller.setDeveloperVerificationUserResponse(sessionId,
                    DEVELOPER_VERIFICATION_USER_RESPONSE_ABORT);
            finish();
        });

    }

    @Nullable
    private AppSnippet generateAppSnippet(@NonNull String resolvedPath) {
        File sourceFile = new File(resolvedPath);
        final PackageInfo packageInfo = PackageUtil.getPackageInfo(this, sourceFile,
                PackageManager.GET_PERMISSIONS);

        // Check for parse errors
        if (packageInfo == null) {
            Log.e(TAG, "Parse error when parsing manifest. Discontinuing installation");
            //show error to user?
            return null;
        }
        if (mLocalLOGV) {
            Log.i(TAG, "Creating snippet for local file " + sourceFile);
        }
        return PackageUtil.getAppSnippet(this, packageInfo.applicationInfo, sourceFile);
    }

    /**
     * Returns whether the user can choose to bypass the verification result and force installation,
     * based on the verification policy and the reason for user action.
     */
    public static boolean isBypassAllowed(
            PackageInstaller.DeveloperVerificationUserConfirmationInfo verificationInfo) {
        int userActionNeededReason = verificationInfo.getUserActionNeededReason();
        int verificationPolicy = verificationInfo.getVerificationPolicy();

        return switch (userActionNeededReason) {
            case DEVELOPER_VERIFICATION_USER_ACTION_NEEDED_REASON_DEVELOPER_BLOCKED -> false;

            case DEVELOPER_VERIFICATION_USER_ACTION_NEEDED_REASON_NETWORK_UNAVAILABLE,
                 DEVELOPER_VERIFICATION_USER_ACTION_NEEDED_REASON_UNKNOWN,
                 DEVELOPER_VERIFICATION_USER_ACTION_NEEDED_REASON_LITE_VERIFICATION ->
                // Only disallow bypass if policy is closed.
                verificationPolicy != DEVELOPER_VERIFICATION_POLICY_BLOCK_FAIL_CLOSED;

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

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

            case DEVELOPER_VERIFICATION_USER_ACTION_NEEDED_REASON_NETWORK_UNAVAILABLE ->
                    R.string.verification_incomplete_summary;

            case DEVELOPER_VERIFICATION_USER_ACTION_NEEDED_REASON_LITE_VERIFICATION ->
                    R.string.lite_verification_summary;

            default -> R.string.cannot_install_package_summary;
        };
    }

    @Override
    protected void onPause() {
        super.onPause();
        // Don't allow the buttons to be clicked as there might be overlays
        Button[] buttons = {mPositiveBtn, mNegativeBtn, mNeutralBtn};
        for (Button button : buttons) {
            if (button != null) {
                button.setEnabled(false);
            }
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        // Re-enable the buttons since they were disabled when activity was paused
        Button[] buttons = {mPositiveBtn, mNegativeBtn, mNeutralBtn};
        for (Button button : buttons) {
            if (button != null) {
                button.setEnabled(true);
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mDialog != null) {
            mDialog.dismiss();
        }
    }
}
+2 −10
Original line number Diff line number Diff line
@@ -98,10 +98,7 @@ public class InstallStart extends Activity {
        String intentAction = intent.getAction();
        final boolean isSessionInstall =
                PackageInstaller.ACTION_CONFIRM_PRE_APPROVAL.equals(intentAction)
                || PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intentAction)
                || (Flags.verificationService()
                && PackageInstaller.ACTION_CONFIRM_DEVELOPER_VERIFICATION.equals(
                        intentAction));
                || PackageInstaller.ACTION_CONFIRM_INSTALL.equals(intentAction);

        // If the activity was started via a PackageInstaller session, we retrieve the originating
        // UID from that session
@@ -216,12 +213,7 @@ public class InstallStart extends Activity {
                originatingUidFromSession);
        nextActivity.putExtra(PackageInstallerActivity.EXTRA_IS_TRUSTED_SOURCE, isTrustedSource);

        if (Flags.verificationService()
                && PackageInstaller.ACTION_CONFIRM_DEVELOPER_VERIFICATION.equals(
                        intentAction)) {
            nextActivity.setClass(this, ConfirmDeveloperVerification.class);
            nextActivity.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
        } else if (isSessionInstall) {
        if (isSessionInstall) {
            nextActivity.setClass(this, PackageInstallerActivity.class);
            nextActivity.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
        } else {
+1 −1
Original line number Diff line number Diff line
@@ -144,7 +144,7 @@ public class DeveloperVerificationConfirmationFragment extends DialogFragment {
     * Returns whether the user can choose to bypass the verification result and force installation,
     * based on the verification policy and the reason for user action.
     */
    private static boolean isBypassAllowed(
    public static boolean isBypassAllowed(
            PackageInstaller.DeveloperVerificationUserConfirmationInfo verificationInfo) {
        int userActionNeededReason = verificationInfo.getUserActionNeededReason();
        int verificationPolicy = verificationInfo.getVerificationPolicy();
+8 −8
Original line number Diff line number Diff line
@@ -26,18 +26,18 @@ import static com.google.common.truth.Truth.assertThat;

import android.content.pm.PackageInstaller.DeveloperVerificationUserConfirmationInfo;

import com.android.packageinstaller.ConfirmDeveloperVerification;
import com.android.packageinstaller.v2.ui.fragments.DeveloperVerificationConfirmationFragment;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

@RunWith(JUnit4.class)
public class VerificationConfirmationDialogTest {
public class DeveloperVerificationConfirmationFragmentTest {

    @Test
    public void policyOpen_packageBlocked_onlyAck() {
        boolean isBypassAllowed = ConfirmDeveloperVerification.isBypassAllowed(
        boolean isBypassAllowed = DeveloperVerificationConfirmationFragment.isBypassAllowed(
                new DeveloperVerificationUserConfirmationInfo(
                        DEVELOPER_VERIFICATION_POLICY_BLOCK_FAIL_OPEN,
                        DEVELOPER_VERIFICATION_FAILED_REASON_DEVELOPER_BLOCKED));
@@ -47,7 +47,7 @@ public class VerificationConfirmationDialogTest {

    @Test
    public void policyOpen_noNetwork_mayBypass() {
        boolean isBypassAllowed = ConfirmDeveloperVerification.isBypassAllowed(
        boolean isBypassAllowed = DeveloperVerificationConfirmationFragment.isBypassAllowed(
                new DeveloperVerificationUserConfirmationInfo(
                        DEVELOPER_VERIFICATION_POLICY_BLOCK_FAIL_OPEN,
                        DEVELOPER_VERIFICATION_FAILED_REASON_NETWORK_UNAVAILABLE));
@@ -57,7 +57,7 @@ public class VerificationConfirmationDialogTest {

    @Test
    public void policyOpen_unknown_mayBypass() {
        boolean isBypassAllowed = ConfirmDeveloperVerification.isBypassAllowed(
        boolean isBypassAllowed = DeveloperVerificationConfirmationFragment.isBypassAllowed(
                new DeveloperVerificationUserConfirmationInfo(
                        DEVELOPER_VERIFICATION_POLICY_BLOCK_FAIL_OPEN,
                        DEVELOPER_VERIFICATION_FAILED_REASON_UNKNOWN));
@@ -67,7 +67,7 @@ public class VerificationConfirmationDialogTest {

    @Test
    public void policyClosed_packageBlocked_onlyAck() {
        boolean isBypassAllowed = ConfirmDeveloperVerification.isBypassAllowed(
        boolean isBypassAllowed = DeveloperVerificationConfirmationFragment.isBypassAllowed(
                new DeveloperVerificationUserConfirmationInfo(
                        DEVELOPER_VERIFICATION_POLICY_BLOCK_FAIL_CLOSED,
                        DEVELOPER_VERIFICATION_FAILED_REASON_DEVELOPER_BLOCKED));
@@ -77,7 +77,7 @@ public class VerificationConfirmationDialogTest {

    @Test
    public void policyClosed_noNetwork_onlyAck() {
        boolean isBypassAllowed = ConfirmDeveloperVerification.isBypassAllowed(
        boolean isBypassAllowed = DeveloperVerificationConfirmationFragment.isBypassAllowed(
                new DeveloperVerificationUserConfirmationInfo(
                        DEVELOPER_VERIFICATION_POLICY_BLOCK_FAIL_CLOSED,
                        DEVELOPER_VERIFICATION_FAILED_REASON_NETWORK_UNAVAILABLE));
@@ -87,7 +87,7 @@ public class VerificationConfirmationDialogTest {

    @Test
    public void policyClosed_unknown_onlyAck() {
        boolean isBypassAllowed = ConfirmDeveloperVerification.isBypassAllowed(
        boolean isBypassAllowed = DeveloperVerificationConfirmationFragment.isBypassAllowed(
                new DeveloperVerificationUserConfirmationInfo(
                        DEVELOPER_VERIFICATION_POLICY_BLOCK_FAIL_CLOSED,
                        DEVELOPER_VERIFICATION_FAILED_REASON_UNKNOWN));