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

Commit 1671605c authored by Sumedh Sen's avatar Sumedh Sen Committed by Song Chun Fan
Browse files

[ADI][UserConfirmation][4/4] Implement ADI on Pia V2

Bug: 360130528
Test: atest PackageInstallerAppUnitTests VerifierServiceTest
Flag: android.content.pm.verification_service
Merged-In: Ibc7b90080686913cb00b6a74d2b945f9d22117ce
Change-Id: Ibc7b90080686913cb00b6a74d2b945f9d22117ce
parent ab82951d
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -5042,6 +5042,14 @@ public class PackageInstaller {
                        return new VerificationUserConfirmationInfo[size];
                    }
                };

        @Override
        public String toString() {
            return "VerificationUserConfirmationInfo{"
                    + "verificationPolicy=" + mVerificationPolicy
                    + ", vericationFailureReason=" + mVerificationFailureReason
                    + '}';
        }
    }

    /**
@@ -5100,9 +5108,13 @@ public class PackageInstaller {
        @Override
        public void writeToParcel(@NonNull Parcel dest, int flags) {
            byte flg = 0;
            if (mIcon != null) flg |= 0x1;
            if (mIcon != null) {
                flg |= 0x1;
            }
            dest.writeByte(flg);
            if (mIcon != null) mIcon.writeToParcel(dest, flags);
            if (mIcon != null) {
                mIcon.writeToParcel(dest, flags);
            }
            dest.writeCharSequence(mLabel);
            dest.writeString8(mLocale.toString());
            dest.writeString8(mPackageName);
+68 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.packageinstaller.v2.model

import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.app.AppOpsManager
import android.app.PendingIntent
@@ -25,10 +26,13 @@ import android.content.ContentResolver
import android.content.Context
import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.Flags
import android.content.pm.PackageInfo
import android.content.pm.PackageInstaller
import android.content.pm.PackageInstaller.SessionInfo
import android.content.pm.PackageInstaller.SessionParams
import android.content.pm.PackageInstaller.VERIFICATION_USER_RESPONSE_ERROR
import android.content.pm.PackageInstaller.VerificationUserConfirmationInfo
import android.content.pm.PackageManager
import android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED
import android.net.Uri
@@ -51,6 +55,7 @@ import com.android.packageinstaller.v2.model.InstallAborted.Companion.DLG_PACKAG
import com.android.packageinstaller.v2.model.InstallUserActionRequired.Companion.USER_ACTION_REASON_ANONYMOUS_SOURCE
import com.android.packageinstaller.v2.model.InstallUserActionRequired.Companion.USER_ACTION_REASON_INSTALL_CONFIRMATION
import com.android.packageinstaller.v2.model.InstallUserActionRequired.Companion.USER_ACTION_REASON_UNKNOWN_SOURCE
import com.android.packageinstaller.v2.model.InstallUserActionRequired.Companion.USER_ACTION_REASON_VERIFICATION_CONFIRMATION
import com.android.packageinstaller.v2.model.PackageUtil.canPackageQuery
import com.android.packageinstaller.v2.model.PackageUtil.generateStubPackageInfo
import com.android.packageinstaller.v2.model.PackageUtil.getAppSnippet
@@ -68,6 +73,7 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch

@SuppressLint("MissingPermission")
class InstallRepository(private val context: Context) {

    private val packageManager: PackageManager = context.packageManager
@@ -149,6 +155,8 @@ class InstallRepository(private val context: Context) {
        isSessionInstall =
            PackageInstaller.ACTION_CONFIRM_PRE_APPROVAL == intent.action
                || PackageInstaller.ACTION_CONFIRM_INSTALL == intent.action
                || (Flags.verificationService()
                && PackageInstaller.ACTION_NOTIFY_VERIFICATION_INCOMPLETE == intent.action)

        sessionId = if (isSessionInstall)
            intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, SessionInfo.INVALID_ID)
@@ -318,6 +326,12 @@ class InstallRepository(private val context: Context) {
    @OptIn(DelicateCoroutinesApi::class)
    fun stageForInstall() {
        val uri = intent.data
        val action = intent.action

        if (PackageInstaller.ACTION_NOTIFY_VERIFICATION_INCOMPLETE == action) {
            _stagingResult.value = InstallVerificationConfirmationRequired()
            return
        }
        if (stagedSessionId != SessionInfo.INVALID_ID
            || isSessionInstall
            || (uri != null && SCHEME_PACKAGE == uri.scheme)
@@ -544,6 +558,15 @@ class InstallRepository(private val context: Context) {
            // mOriginatingURI = null;
            // mReferrerURI = null;
            pendingUserActionReason = info.getPendingUserActionReason()
        } else if (PackageInstaller.ACTION_NOTIFY_VERIFICATION_INCOMPLETE == intent.action) {
            val info = packageInstaller.getSessionInfo(sessionId)
            val resolvedPath = info?.resolvedBaseApkPath
            if (info == null || !info.isSealed || resolvedPath == null) {
                Log.e(LOG_TAG, "Session $sessionId in funky state; ignoring")
                return InstallAborted(ABORT_REASON_INTERNAL_ERROR)
            }
            packageSource = Uri.fromFile(File(resolvedPath))
            pendingUserActionReason = info.getPendingUserActionReason()
        } else {
            // Two possible origins:
            // 1. Installation with SCHEME_PACKAGE.
@@ -794,6 +817,39 @@ class InstallRepository(private val context: Context) {
        return true
    }

    fun requestVerificationConfirmation(): InstallStage {
        var confirmationSnippet: InstallStage = generateConfirmationSnippet()

        if (confirmationSnippet.stageCode == InstallStage.STAGE_ABORTED) {
            packageInstaller.setVerificationUserResponse(
                sessionId, VERIFICATION_USER_RESPONSE_ERROR
            )
            return confirmationSnippet
        }

        val verificationInfo: VerificationUserConfirmationInfo? =
            packageInstaller.getVerificationUserConfirmationInfo(sessionId)
        if (verificationInfo == null) {
            Log.e(LOG_TAG, "Could not get VerificationInfo for sessionId $sessionId")
            packageInstaller.setVerificationUserResponse(
                sessionId, VERIFICATION_USER_RESPONSE_ERROR
            )
            return InstallAborted(ABORT_REASON_INTERNAL_ERROR)
        }

        confirmationSnippet = confirmationSnippet as InstallUserActionRequired
        val appSnippet = PackageUtil.getAppSnippet(
                context, confirmationSnippet.appLabel, confirmationSnippet.appIcon)

        // Since InstallUserActionRequired returned by generateConfirmationSnippet is immutable,
        // create a new InstallUserActionRequired with the required data
        return InstallUserActionRequired(
            actionReason = USER_ACTION_REASON_VERIFICATION_CONFIRMATION,
            appSnippet = appSnippet,
            verificationInfo = verificationInfo
        )
    }

    /**
     * Once the user returns from Settings related to installing from unknown sources, reattempt
     * the installation if the source app is granted permission to install other apps. Abort the
@@ -1046,6 +1102,18 @@ class InstallRepository(private val context: Context) {
        cleanupStagingSession()
    }

    fun setUserVerificationResponse(responseCode: Int) {
        if (PackageInstaller.ACTION_NOTIFY_VERIFICATION_INCOMPLETE != intent.action) {
            Log.e(LOG_TAG, "Cannot set verification response for this request: $intent")
            _installResult.value = InstallAborted(ABORT_REASON_INTERNAL_ERROR)
            return
        }
        packageInstaller.setVerificationUserResponse(sessionId, responseCode)
        _installResult.value = InstallAborted(
            ABORT_REASON_DONE, activityResultCode = Activity.RESULT_OK
        )
    }

    val stagingProgress: LiveData<Int>
        get() = sessionStager?.progress ?: MutableLiveData(0)

+8 −0
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ import android.content.Intent
import android.content.pm.PackageInstaller
import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
import com.android.packageinstaller.v2.model.InstallAborted.Companion.ABORT_REASON_INTERNAL_ERROR
import com.android.packageinstaller.v2.model.InstallAborted.Companion.ABORT_REASON_POLICY

sealed class InstallStage(val stageCode: Int) {

@@ -33,6 +35,7 @@ sealed class InstallStage(val stageCode: Int) {
        const val STAGE_INSTALLING = 4
        const val STAGE_SUCCESS = 5
        const val STAGE_FAILED = 6
        const val STAGE_VERIFICATION_CONFIRMATION_REQUIRED = 7
    }
}

@@ -47,6 +50,7 @@ data class InstallUserActionRequired(
    val existingUpdateOwnerLabel: CharSequence? = null,
    val requestedUpdateOwnerLabel: CharSequence? = null,
    val unknownSourcePackageName: String? = null,
    val verificationInfo: PackageInstaller.VerificationUserConfirmationInfo? = null,
) : InstallStage(STAGE_USER_ACTION_REQUIRED) {

    val appIcon: Drawable?
@@ -59,6 +63,7 @@ data class InstallUserActionRequired(
        const val USER_ACTION_REASON_UNKNOWN_SOURCE = 0
        const val USER_ACTION_REASON_ANONYMOUS_SOURCE = 1
        const val USER_ACTION_REASON_INSTALL_CONFIRMATION = 2
        const val USER_ACTION_REASON_VERIFICATION_CONFIRMATION = 3
    }
}

@@ -144,3 +149,6 @@ data class InstallAborted(
        const val DLG_PACKAGE_ERROR = 1
    }
}

class InstallVerificationConfirmationRequired :
    InstallStage(STAGE_VERIFICATION_CONFIRMATION_REQUIRED)
+9 −0
Original line number Diff line number Diff line
@@ -333,6 +333,15 @@ object PackageUtil {
        }
    }

    /**
     * Generates an [AppSnippet] containing specified appIcon and appLabel
     */
    @JvmStatic
    fun getAppSnippet(context: Context, label: CharSequence?, icon: Drawable?): AppSnippet {
        val largeIconSize = getLargeIconSize(context)
        return AppSnippet(label, icon, largeIconSize)
    }

    private fun getLargeIconSize(context: Context): Int {
        val am = context.getSystemService<ActivityManager>(ActivityManager::class.java)
        return am.launcherLargeIconSize
+2 −0
Original line number Diff line number Diff line
@@ -45,4 +45,6 @@ interface InstallActionListener {
     * Launch the intent to open Storage Manager in Settings app.
     */
    fun sendManageAppsIntent()

    fun setVerificationUserResponse(responseCode: Int)
}
Loading