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

Commit 353ed172 authored by Sumedh Sen's avatar Sumedh Sen Committed by Android (Google) Code Review
Browse files

Merge changes I65b9a5c2,I9267817b into main

* changes:
  [piav2] Code cleanup
  [piav2] Simplify UIDs in PacakgeInstaller app
parents 72977ba6 e8fb8905
Loading
Loading
Loading
Loading
+75 −63
Original line number Diff line number Diff line
@@ -95,9 +95,22 @@ class InstallRepository(private val context: Context) {
     */
    var stagedSessionId = SessionInfo.INVALID_ID
        private set

    /**
     * UID of the last caller of Pia. This can point to a 3P installer if it uses intents to install
     * an APK, or receives a
     * [STATUS_PENDING_USER_ACTION][PackageInstaller.STATUS_PENDING_USER_ACTION] status code.
     * It may point to Pia, when it receives the STATUS_PENDING_USER_ACTION status code in case of
     * an update-ownership change.
     */
    private var callingUid = Process.INVALID_UID

    /**
     * UID of the origin of the installation. This UID is used to fetch the app-label of the
     * source of the install, and also check whether the source app has the AppOp to install other
     * apps.
     */
    private var originatingUid = Process.INVALID_UID
    private var originatingUidFromSessionInfo = Process.INVALID_UID
    private var callingPackage: String? = null
    private var sessionStager: SessionStager? = null
    private lateinit var intent: Intent
@@ -136,68 +149,60 @@ class InstallRepository(private val context: Context) {
        stagedSessionId = intent.getIntExtra(EXTRA_STAGED_SESSION_ID, SessionInfo.INVALID_ID)

        callingPackage = callerInfo.packageName

        // Uid of the source package, coming from ActivityManager
        callingUid = callerInfo.uid
        if (callingUid == Process.INVALID_UID) {
            Log.e(LOG_TAG, "Could not determine the launching uid.")

        val sourceInfo: ApplicationInfo? = getSourceInfo(callingPackage)
        if (callingUid == Process.INVALID_UID && sourceInfo == null) {
            // Caller's identity could not be determined. Abort the install
            Log.e(LOG_TAG, "Cannot determine caller since UID is invalid and sourceInfo is null")
            return InstallAborted(ABORT_REASON_INTERNAL_ERROR)
        }

        originatingUidFromSessionInfo = callingUid
        originatingUid = callingUid
        val sessionInfo: SessionInfo? =
            if (sessionId != SessionInfo.INVALID_ID)
                packageInstaller.getSessionInfo(sessionId)
            else null
        if (sessionInfo != null) {
            callingPackage = sessionInfo.installerPackageName
            callingAttributionTag = sessionInfo.installerAttributionTag
            if (sessionInfo.originatingUid != Process.INVALID_UID) {
                originatingUidFromSessionInfo = sessionInfo.originatingUid
                originatingUid = sessionInfo.originatingUid
            }
        }

        val sourceInfo: ApplicationInfo? = getSourceInfo(callingPackage)
        // Uid of the source package, with a preference to uid from ApplicationInfo
        originatingUid = sourceInfo?.uid ?: callingUid
        appOpRequestInfo = AppOpRequestInfo(
            getPackageNameForUid(context, originatingUid, callingPackage),
            originatingUid, callingAttributionTag
            originatingUid,
            callingAttributionTag
        )

        if (localLogv) {
            Log.i(LOG_TAG, "Intent: $intent\n" +
            Log.i(
                LOG_TAG, "Intent: $intent\n" +
                    "sessionId: $sessionId\n" +
                    "staged sessionId: $stagedSessionId\n" +
                    "calling package: $callingPackage\n" +
                    "callingUid: $callingUid\n" +
                "originatingUid: $originatingUid")
        }

        if (callingUid == Process.INVALID_UID && sourceInfo == null) {
            // Caller's identity could not be determined. Abort the install
            Log.e(LOG_TAG, "Cannot determine caller since UID is invalid and sourceInfo is null")
            return InstallAborted(ABORT_REASON_INTERNAL_ERROR)
                    "originatingUid: $originatingUid\n" +
                    "sourceInfo: $sourceInfo"
            )
        }

        if ((sessionId != SessionInfo.INVALID_ID
                && !isCallerSessionOwner(packageInstaller, originatingUid, sessionId))
                && !isCallerSessionOwner(packageInstaller, callingUid, sessionId))
            || (stagedSessionId != SessionInfo.INVALID_ID
                && !isCallerSessionOwner(packageInstaller, Process.myUid(), stagedSessionId))
        ) {
            Log.e(LOG_TAG, "UID is not the owner of the session:\n" +
                "CallingUid: $originatingUid | SessionId: $sessionId\n" +
                "My UID: ${Process.myUid()} | StagedSessionId: $stagedSessionId")
            Log.e(
                LOG_TAG, "UID is not the owner of the session:\n" +
                    "CallingUid: $callingUid | SessionId: $sessionId\n" +
                    "My UID: ${Process.myUid()} | StagedSessionId: $stagedSessionId"
            )
            return InstallAborted(ABORT_REASON_INTERNAL_ERROR)
        }

        isTrustedSource = isInstallRequestFromTrustedSource(sourceInfo, this.intent, originatingUid)
        if (!isInstallPermissionGrantedOrRequested(
                context, callingUid, originatingUid, isTrustedSource
            )
        ) {
            Log.e(LOG_TAG, "UID $originatingUid needs to declare " +
                Manifest.permission.REQUEST_INSTALL_PACKAGES
            )
        isTrustedSource = isInstallRequestFromTrustedSource(sourceInfo, this.intent, callingUid)
        if (!isInstallPermissionGrantedOrRequested(context, callingUid, isTrustedSource)) {
            return InstallAborted(ABORT_REASON_INTERNAL_ERROR)
        }

@@ -230,12 +235,12 @@ class InstallRepository(private val context: Context) {
    private fun isInstallRequestFromTrustedSource(
        sourceInfo: ApplicationInfo?,
        intent: Intent,
        originatingUid: Int,
        callingUid: Int,
    ): Boolean {
        val isNotUnknownSource = intent.getBooleanExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false)
        return (sourceInfo != null && sourceInfo.isPrivilegedApp
            && (isNotUnknownSource
            || isPermissionGranted(context, Manifest.permission.INSTALL_PACKAGES, originatingUid)))
            || isPermissionGranted(context, Manifest.permission.INSTALL_PACKAGES, callingUid)))
    }

    private fun getDevicePolicyRestrictions(): String? {
@@ -401,7 +406,8 @@ class InstallRepository(private val context: Context) {
                Log.e(LOG_TAG, "Cannot parse package $debugPathName. Assuming defaults.", e)
                params.setSize(pfd.statSize)
            } catch (e: IOException) {
                Log.e(LOG_TAG, "Cannot calculate installed size $debugPathName. " +
                Log.e(
                    LOG_TAG, "Cannot calculate installed size $debugPathName. " +
                        "Try only apk size.", e
                )
            }
@@ -661,10 +667,9 @@ class InstallRepository(private val context: Context) {
        if (isAppUpdating(pkgInfo)) {
            val existingUpdateOwnerLabel = getExistingUpdateOwnerLabel(pkgInfo)

            val originatingPackageNameFromSessionInfo =
                getPackageNameForUid(context, originatingUidFromSessionInfo, callingPackage)
            val requestedUpdateOwnerLabel =
                getApplicationLabel(originatingPackageNameFromSessionInfo)
            val originatingPackageName =
                getPackageNameForUid(context, originatingUid, callingPackage)
            val requestedUpdateOwnerLabel = getApplicationLabel(originatingPackageName)

            if (!TextUtils.isEmpty(existingUpdateOwnerLabel)
                && userActionReason == PackageInstaller.REASON_REMIND_OWNERSHIP
@@ -768,14 +773,14 @@ class InstallRepository(private val context: Context) {
    }

    private fun handleUnknownSources(requestInfo: AppOpRequestInfo): InstallStage {
        if (requestInfo.callingPackage == null) {
        if (requestInfo.originatingPackage == null) {
            Log.i(LOG_TAG, "No source found for package " + newPackageInfo?.packageName)
            return InstallUserActionRequired(USER_ACTION_REASON_ANONYMOUS_SOURCE)
        }
        // Shouldn't use static constant directly, see b/65534401.
        val appOpStr = AppOpsManager.permissionToOp(Manifest.permission.REQUEST_INSTALL_PACKAGES)
        val appOpMode = appOpsManager!!.noteOpNoThrow(
            appOpStr!!, requestInfo.originatingUid, requestInfo.callingPackage,
            appOpStr!!, requestInfo.originatingUid, requestInfo.originatingPackage,
            requestInfo.attributionTag, "Started package installation activity"
        )
        if (localLogv) {
@@ -786,20 +791,20 @@ class InstallRepository(private val context: Context) {
            AppOpsManager.MODE_DEFAULT, AppOpsManager.MODE_ERRORED -> {
                if (appOpMode == AppOpsManager.MODE_DEFAULT) {
                    appOpsManager.setMode(
                        appOpStr, requestInfo.originatingUid, requestInfo.callingPackage,
                        appOpStr, requestInfo.originatingUid, requestInfo.originatingPackage,
                        AppOpsManager.MODE_ERRORED
                    )
                }
                try {
                    val sourceInfo =
                        packageManager.getApplicationInfo(requestInfo.callingPackage, 0)
                        packageManager.getApplicationInfo(requestInfo.originatingPackage, 0)
                    val sourceAppSnippet = getAppSnippet(context, sourceInfo)
                    InstallUserActionRequired(
                        USER_ACTION_REASON_UNKNOWN_SOURCE, appSnippet = sourceAppSnippet,
                        dialogMessage = requestInfo.callingPackage
                        sourceApp = requestInfo.originatingPackage
                    )
                } catch (e: PackageManager.NameNotFoundException) {
                    Log.e(LOG_TAG, "Did not find appInfo for " + requestInfo.callingPackage)
                    Log.e(LOG_TAG, "Did not find appInfo for " + requestInfo.originatingPackage)
                    InstallAborted(ABORT_REASON_INTERNAL_ERROR)
                }
            }
@@ -841,8 +846,10 @@ class InstallRepository(private val context: Context) {
                setStageBasedOnResult(PackageInstaller.STATUS_SUCCESS, -1, null)
            } catch (e: PackageManager.NameNotFoundException) {
                setStageBasedOnResult(
                    PackageInstaller.STATUS_FAILURE, PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
                    null)
                    PackageInstaller.STATUS_FAILURE,
                    PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
                    null
                )
            }
            return
        }
@@ -862,7 +869,8 @@ class InstallRepository(private val context: Context) {
            }
        } catch (e: OutOfIdsException) {
            setStageBasedOnResult(
                PackageInstaller.STATUS_FAILURE, PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null)
                PackageInstaller.STATUS_FAILURE, PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null
            )
            return
        }
        val broadcastIntent = Intent(BROADCAST_ACTION)
@@ -880,7 +888,8 @@ class InstallRepository(private val context: Context) {
            Log.e(LOG_TAG, "Session $stagedSessionId could not be opened.", e)
            packageInstaller.abandonSession(stagedSessionId)
            setStageBasedOnResult(
                PackageInstaller.STATUS_FAILURE, PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null)
                PackageInstaller.STATUS_FAILURE, PackageManager.INSTALL_FAILED_INTERNAL_ERROR, null
            )
        }
    }

@@ -890,9 +899,11 @@ class InstallRepository(private val context: Context) {
        message: String?,
    ) {
        if (localLogv) {
            Log.i(LOG_TAG, "Status code: $statusCode\n" +
            Log.i(
                LOG_TAG, "Status code: $statusCode\n" +
                    "legacy status: $legacyStatus\n" +
                "message: $message")
                    "message: $message"
            )
        }
        if (statusCode == PackageInstaller.STATUS_SUCCESS) {
            val shouldReturnResult = intent.getBooleanExtra(Intent.EXTRA_RETURN_RESULT, false)
@@ -905,11 +916,12 @@ class InstallRepository(private val context: Context) {
            _installResult.setValue(InstallSuccess(appSnippet, shouldReturnResult, resultIntent))
        } else {
            if (statusCode != PackageInstaller.STATUS_FAILURE_ABORTED) {
                _installResult.setValue(InstallFailed(appSnippet, statusCode, legacyStatus, message))
                _installResult.setValue(
                    InstallFailed(appSnippet, statusCode, legacyStatus, message)
                )
            } else {
                _installResult.setValue(InstallAborted(ABORT_REASON_INTERNAL_ERROR))
            }

        }
    }

@@ -953,7 +965,7 @@ class InstallRepository(private val context: Context) {

    data class CallerInfo(val packageName: String?, val uid: Int)
    data class AppOpRequestInfo(
        val callingPackage: String?,
        val originatingPackage: String?,
        val originatingUid: Int,
        val attributionTag: String?,
    )
+4 −1
Original line number Diff line number Diff line
@@ -43,7 +43,10 @@ data class InstallUserActionRequired(
    val actionReason: Int,
    private val appSnippet: PackageUtil.AppSnippet? = null,
    val isAppUpdating: Boolean = false,
    val dialogMessage: String? = null,
    /**
     * This holds either a package name or the app label of the install source.
     */
    val sourceApp: String? = null,
) : InstallStage(STAGE_USER_ACTION_REQUIRED) {

    val appIcon: Drawable?
+25 −24
Original line number Diff line number Diff line
@@ -128,18 +128,19 @@ object PackageUtil {

    /**
     * @param context the [Context] object
     * @param callingUid the UID of the caller who's permission is being checked
     * @param originatingUid the UID from where install is being originated. This could be same as
     * callingUid or it will be the UID of the package performing a session based install
     * @param isTrustedSource whether install request is coming from a privileged app or an app that
     * has [Manifest.permission.INSTALL_PACKAGES] permission granted
     * @return `true` if the package is granted the said permission
     * @param callingUid the UID of the caller of Pia
     * @param isTrustedSource indicates whether install request is coming from a privileged app
     * that has passed EXTRA_NOT_UNKNOWN_SOURCE as `true` in the installation intent, or that has
     * the [INSTALL_PACKAGES][Manifest.permission.INSTALL_PACKAGES] permission granted.
     *
     * @return `true` if the package is either a system downloads provider, a document manager,
     * a trusted source, or has declared the
     * [REQUEST_INSTALL_PACKAGES][Manifest.permission.REQUEST_INSTALL_PACKAGES] in its manifest.
     */
    @JvmStatic
    fun isInstallPermissionGrantedOrRequested(
        context: Context,
        callingUid: Int,
        originatingUid: Int,
        isTrustedSource: Boolean,
    ): Boolean {
        val isDocumentsManager =
@@ -148,19 +149,18 @@ object PackageUtil {
            getSystemDownloadsProviderInfo(context.packageManager, callingUid) != null

        if (!isTrustedSource && !isSystemDownloadsProvider && !isDocumentsManager) {
            val targetSdkVersion = getMaxTargetSdkVersionForUid(context, originatingUid)
            val targetSdkVersion = getMaxTargetSdkVersionForUid(context, callingUid)
            if (targetSdkVersion < 0) {
                // Invalid originating uid supplied. Abort install.
                Log.w(LOG_TAG, "Cannot get target sdk version for uid $originatingUid")
                // Invalid calling uid supplied. Abort install.
                Log.e(LOG_TAG, "Cannot get target SDK version for uid $callingUid")
                return false
            } else if (targetSdkVersion >= Build.VERSION_CODES.O
                && !isUidRequestingPermission(
                    context.packageManager, originatingUid,
                    Manifest.permission.REQUEST_INSTALL_PACKAGES
                    context.packageManager, callingUid, Manifest.permission.REQUEST_INSTALL_PACKAGES
                )
            ) {
                Log.e(
                    LOG_TAG, "Requesting uid " + originatingUid + " needs to declare permission "
                    LOG_TAG, "Requesting uid " + callingUid + " needs to declare permission "
                        + Manifest.permission.REQUEST_INSTALL_PACKAGES
                )
                return false
@@ -204,13 +204,13 @@ object PackageUtil {
     * @return `true` if the caller is the session owner
     */
    @JvmStatic
    fun isCallerSessionOwner(pi: PackageInstaller, originatingUid: Int, sessionId: Int): Boolean {
        if (originatingUid == Process.ROOT_UID) {
    fun isCallerSessionOwner(pi: PackageInstaller, callingUid: Int, sessionId: Int): Boolean {
        if (callingUid == Process.ROOT_UID) {
            return true
        }
        val sessionInfo = pi.getSessionInfo(sessionId) ?: return false
        val installerUid = sessionInfo.getInstallerUid()
        return originatingUid == installerUid
        return callingUid == installerUid
    }

    /**
@@ -362,8 +362,8 @@ object PackageUtil {
     * @return the packageName corresponding to a UID.
     */
    @JvmStatic
    fun getPackageNameForUid(context: Context, sourceUid: Int, callingPackage: String?): String? {
        if (sourceUid == Process.INVALID_UID) {
    fun getPackageNameForUid(context: Context, uid: Int, preferredPkgName: String?): String? {
        if (uid == Process.INVALID_UID) {
            return null
        }
        // If the sourceUid belongs to the system downloads provider, we explicitly return the
@@ -371,20 +371,21 @@ object PackageUtil {
        // packages, resulting in uncertainty about which package will end up first in the list
        // of packages associated with this UID
        val pm = context.packageManager
        val systemDownloadProviderInfo = getSystemDownloadsProviderInfo(pm, sourceUid)
        val systemDownloadProviderInfo = getSystemDownloadsProviderInfo(pm, uid)
        if (systemDownloadProviderInfo != null) {
            return systemDownloadProviderInfo.packageName
        }
        val packagesForUid = pm.getPackagesForUid(sourceUid) ?: return null

        val packagesForUid = pm.getPackagesForUid(uid) ?: return null
        if (packagesForUid.size > 1) {
            if (callingPackage != null) {
            Log.i(LOG_TAG, "Multiple packages found for source uid $uid")
            if (preferredPkgName != null) {
                for (packageName in packagesForUid) {
                    if (packageName == callingPackage) {
                    if (packageName == preferredPkgName) {
                        return packageName
                    }
                }
            }
            Log.i(LOG_TAG, "Multiple packages found for source uid $sourceUid")
        }
        return packagesForUid[0]
    }
@@ -439,7 +440,7 @@ object PackageUtil {
     */
    data class AppSnippet(var label: CharSequence?, var icon: Drawable?) {
        override fun toString(): String {
            return "AppSnippet[label = ${label}, hasIcon = ${icon != null}]"
            return "AppSnippet[label = $label, hasIcon = ${icon != null}]"
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -63,7 +63,7 @@ public class ExternalSourcesBlockedFragment extends DialogFragment {
            .setMessage(R.string.untrusted_external_source_warning)
            .setPositiveButton(R.string.external_sources_settings,
                (dialog, which) -> mInstallActionListener.sendUnknownAppsIntent(
                    mDialogData.getDialogMessage()))
                    mDialogData.getSourceApp()))
            .setNegativeButton(R.string.cancel,
                (dialog, which) -> mInstallActionListener.onNegativeResponse(
                    mDialogData.getStageCode()))
+5 −4
Original line number Diff line number Diff line
@@ -64,7 +64,7 @@ public class InstallConfirmationFragment extends DialogFragment {

        int positiveBtnTextRes;
        if (mDialogData.isAppUpdating()) {
            if (mDialogData.getDialogMessage() != null) {
            if (mDialogData.getSourceApp() != null) {
                positiveBtnTextRes = R.string.update_anyway;
            } else {
                positiveBtnTextRes = R.string.update;
@@ -88,9 +88,10 @@ public class InstallConfirmationFragment extends DialogFragment {
        TextView viewToEnable;
        if (mDialogData.isAppUpdating()) {
            viewToEnable = dialogView.requireViewById(R.id.install_confirm_question_update);
            String dialogMessage = mDialogData.getDialogMessage();
            if (dialogMessage != null) {
                viewToEnable.setText(Html.fromHtml(dialogMessage, Html.FROM_HTML_MODE_LEGACY));
            String sourcePackageName = mDialogData.getSourceApp();
            if (sourcePackageName != null) {
                // Show the update-ownership change message
                viewToEnable.setText(Html.fromHtml(sourcePackageName, Html.FROM_HTML_MODE_LEGACY));
            }
        } else {
            viewToEnable = dialogView.requireViewById(R.id.install_confirm_question);