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

Commit 09af5818 authored by Ivan Chiang's avatar Ivan Chiang
Browse files

[PM] Use the originating uid from the intent if needed

If the intent is from the system document app or the system downloads
provider, we can trust it to use the originating uid from it. It can
show the correct install information from the uid.

Flag: EXEMPT Bug fix
Test: atest CtsPackageInstallerCUJInstallationTestCases
Test: atest CtsPackageInstallerCUJUpdateOwnerShipTestCases
Test: manual
      1. Download one app via 3rd party browser
      2. Uninstall the 3rd party browser
      3. Start the Documentsui -> Downloads root
      4. Click the APK
Bug: 419738096

Change-Id: Ic92fc3c4ffc6453ca02852edefaa8b1358962f2c
parent a1ea8369
Loading
Loading
Loading
Loading
+34 −13
Original line number Diff line number Diff line
@@ -114,12 +114,13 @@ public class InstallStart extends Activity {
        final int sessionId = (isSessionInstall
                ? intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, SessionInfo.INVALID_ID)
                : SessionInfo.INVALID_ID);
        int originatingUidFromSession = callingUid;
        if (sessionId != SessionInfo.INVALID_ID) {
            PackageInstaller.SessionInfo sessionInfo = mPackageInstaller.getSessionInfo(sessionId);
            if (sessionInfo != null) {
                callingAttributionTag = sessionInfo.getInstallerAttributionTag();
                if (sessionInfo.getOriginatingUid() != Process.INVALID_UID) {
                    originatingUid = sessionInfo.getOriginatingUid();
                    originatingUidFromSession = sessionInfo.getOriginatingUid();
                }
            }
        }
@@ -136,24 +137,40 @@ public class InstallStart extends Activity {
        boolean isSystemDownloadsProvider = PackageUtil.getSystemDownloadsProviderInfo(
                                                mPackageManager, callingUid) != null;

        // By default, the originatingUid is callingUid. If the caller is the system download
        // provider or the documents manager, we parse the originatingUid from the
        // Intent.EXTRA_ORIGINATING_UID. And we check the appOps permission for the originatingUid
        // later.
        if (isDocumentsManager || isSystemDownloadsProvider) {
            // The originating uid from the intent. We only trust/use this if it comes from either
            // the document manager app or the downloads provider. It may be Process.INVALID_UID if
            // the original owner App is not installed on the device now.
            originatingUid = getIntent().getIntExtra(Intent.EXTRA_ORIGINATING_UID,
                    Process.INVALID_UID);
        }

        boolean isPrivilegedAndKnown = (sourceInfo != null && sourceInfo.isPrivilegedApp()) &&
            intent.getBooleanExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, false);
        boolean isInstallPkgPermissionGranted =
            checkPermission(Manifest.permission.INSTALL_PACKAGES, /* pid= */ -1, callingUid)
                    == PackageManager.PERMISSION_GRANTED;
        boolean isInstallPkgPermissionGranted = originatingUid != Process.INVALID_UID
                && checkPermission(Manifest.permission.INSTALL_PACKAGES, /* pid= */ -1,
                originatingUid) == PackageManager.PERMISSION_GRANTED;

        boolean isTrustedSource = isPrivilegedAndKnown || isInstallPkgPermissionGranted;

        if (!isTrustedSource && !isSystemDownloadsProvider && !isDocumentsManager
                && callingUid != Process.INVALID_UID) {
            final int targetSdkVersion = getMaxTargetSdkVersionForUid(this, callingUid);
        // In general case, the originatingUid is callingUid. If callingUid is INVALID_UID, return
        // InstallAborted in the check above. When the originatingUid is INVALID_UID here, it means
        // the originatingUid is from the system download manager or the system documents manager,
        // and the package doesn't exist on the device. For this case, we don't need to check the
        // permission for the originatingUid. The package doesn't exist.
        if (!isTrustedSource && originatingUid != Process.INVALID_UID) {
            final int targetSdkVersion = getMaxTargetSdkVersionForUid(this, originatingUid);
            if (targetSdkVersion < 0) {
                Log.e(TAG, "Cannot get target sdk version for uid " + callingUid);
                Log.e(TAG, "Cannot get target sdk version for uid " + originatingUid);
                // Invalid originating uid supplied. Abort install.
                mAbortInstall = true;
            } else if (targetSdkVersion >= Build.VERSION_CODES.O && !isUidRequestingPermission(
                callingUid, Manifest.permission.REQUEST_INSTALL_PACKAGES)) {
                Log.e(TAG, "Requesting uid " + callingUid + " needs to declare permission "
                    originatingUid, Manifest.permission.REQUEST_INSTALL_PACKAGES)) {
                Log.e(TAG, "Requesting uid " + originatingUid + " needs to declare permission "
                        + Manifest.permission.REQUEST_INSTALL_PACKAGES);
                mAbortInstall = true;
            }
@@ -182,6 +199,7 @@ public class InstallStart extends Activity {
        }

        if (mAbortInstall) {
            android.util.Log.d(TAG, "Abort the installation");
            setResult(RESULT_CANCELED);
            if (mShouldFinish) {
                finish();
@@ -200,6 +218,8 @@ public class InstallStart extends Activity {
                callingAttributionTag);
        nextActivity.putExtra(PackageInstallerActivity.EXTRA_ORIGINAL_SOURCE_INFO, sourceInfo);
        nextActivity.putExtra(Intent.EXTRA_ORIGINATING_UID, originatingUid);
        nextActivity.putExtra(PackageInstallerActivity.EXTRA_ORIGINATING_UID_FROM_SESSION_INFO,
                originatingUidFromSession);
        nextActivity.putExtra(PackageInstallerActivity.EXTRA_IS_TRUSTED_SOURCE, isTrustedSource);

        if (isSessionInstall) {
@@ -208,9 +228,9 @@ public class InstallStart extends Activity {
        } else {
            Uri packageUri = intent.getData();

            if (packageUri != null
                    && packageUri.getScheme().equals(ContentResolver.SCHEME_CONTENT)
                    && canPackageQuery(callingUid, packageUri)) {
            if (packageUri != null && packageUri.getScheme().equals(ContentResolver.SCHEME_CONTENT)
                    && (originatingUid == Process.INVALID_UID
                    || canPackageQuery(originatingUid, packageUri))) {
                // [IMPORTANT] This path is deprecated, but should still work. Only necessary
                // features should be added.

@@ -230,6 +250,7 @@ public class InstallStart extends Activity {
            }
        }

        android.util.Log.d(TAG, "nextActivity = " + nextActivity);
        if (nextActivity != null) {
            try {
                startActivity(nextActivity);
+12 −1
Original line number Diff line number Diff line
@@ -84,6 +84,8 @@ public class PackageInstallerActivity extends Activity {
    static final String EXTRA_ORIGINAL_SOURCE_INFO = "EXTRA_ORIGINAL_SOURCE_INFO";
    static final String EXTRA_STAGED_SESSION_ID = "EXTRA_STAGED_SESSION_ID";
    static final String EXTRA_APP_SNIPPET = "EXTRA_APP_SNIPPET";
    static final String EXTRA_ORIGINATING_UID_FROM_SESSION_INFO =
            "EXTRA_ORIGINATING_UID_FROM_SESSION_INFO";
    static final String EXTRA_IS_TRUSTED_SOURCE = "EXTRA_IS_TRUSTED_SOURCE";
    private static final String ALLOW_UNKNOWN_SOURCES_KEY =
            PackageInstallerActivity.class.getName() + "ALLOW_UNKNOWN_SOURCES_KEY";
@@ -97,6 +99,10 @@ public class PackageInstallerActivity extends Activity {
     * The package name corresponding to #mOriginatingUid
     */
    private String mOriginatingPackage;
    /**
     * The package name corresponding to the app updater in the update-ownership confirmation dialog
     */
    private String mOriginatingPackageFromSessionInfo;
    private int mActivityResultCode = Activity.RESULT_CANCELED;
    private int mPendingUserActionReason = -1;

@@ -149,7 +155,8 @@ public class PackageInstallerActivity extends Activity {
            viewToEnable = mDialog.requireViewById(R.id.install_confirm_question_update);

            final CharSequence existingUpdateOwnerLabel = getExistingUpdateOwnerLabel();
            final CharSequence requestedUpdateOwnerLabel = getApplicationLabel(mOriginatingPackage);
            final CharSequence requestedUpdateOwnerLabel =
                    getApplicationLabel(mOriginatingPackageFromSessionInfo);
            if (!TextUtils.isEmpty(existingUpdateOwnerLabel)
                    && mPendingUserActionReason == PackageInstaller.REASON_REMIND_OWNERSHIP) {
                String updateOwnerString =
@@ -382,6 +389,10 @@ public class PackageInstallerActivity extends Activity {
        mOriginatingUid = intent.getIntExtra(Intent.EXTRA_ORIGINATING_UID, Process.INVALID_UID);
        mOriginatingPackage = (mOriginatingUid != Process.INVALID_UID)
                ? getPackageNameForUid(mOriginatingUid) : null;
        int originatingUidFromSessionInfo =
                intent.getIntExtra(EXTRA_ORIGINATING_UID_FROM_SESSION_INFO, Process.INVALID_UID);
        mOriginatingPackageFromSessionInfo = (originatingUidFromSessionInfo != Process.INVALID_UID)
                ? getPackageNameForUid(originatingUidFromSessionInfo) : mCallingPackage;

        final Object packageSource;
        if (PackageInstaller.ACTION_CONFIRM_INSTALL.equals(action)) {