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

Commit ecf837ae authored by Azhara Assanova's avatar Azhara Assanova
Browse files

Add EXTRA_STREAM to ComponentCaller#checkContentUriPermission

ComponentCaller#checkContentUriPermission only works for content URIs
passed at launch and specifically URIs passed in Intent#getData and
Intent#getClipData. This change adds Intent#EXTRA_STREAM to that list as
it is one of the common ways for apps to pass URIs.

EXTRA_STREAM only works for URIs that the system can unparcel.

Bug: 293467489
Test: atest CtsAndroidAppTestCases:android.app.cts.ComponentCallerTest
Change-Id: I94437b9eecd16856e0fe91c1b66793e17ecd3e4e
parent b43432bc
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -137,16 +137,18 @@ public final class ComponentCaller {
     *     <li>This is not a real time check, i.e. the permissions have been computed at launch
     *     time.
     *     <li>This method will return the correct result for content URIs passed at launch time,
     *     specifically the ones from {@link Intent#getData()}, and {@link Intent#getClipData()} in
     *     the intent of {@code startActivity(intent)}. For others, it will throw an
     *     {@link IllegalArgumentException}.
     *     specifically the ones from {@link Intent#getData()}, {@link Intent#EXTRA_STREAM}, and
     *     {@link Intent#getClipData()} in the intent of {@code startActivity(intent)}. For others,
     *     it will throw an {@link IllegalArgumentException}.
     * </ul>
     *
     * @param uri The content uri that is being checked
     * @param modeFlags The access modes to check
     * @return {@link PackageManager#PERMISSION_GRANTED} if this activity caller is allowed to
     *         access that uri, or {@link PackageManager#PERMISSION_DENIED} if it is not
     * @throws IllegalArgumentException if uri is a non-content URI or it wasn't passed at launch
     * @throws IllegalArgumentException if uri is a non-content URI or it wasn't passed at launch in
     *                                  {@link Intent#getData()}, {@link Intent#EXTRA_STREAM}, and
     *                                  {@link Intent#getClipData()}
     * @throws SecurityException if you don't have access to uri
     *
     * @see android.content.Context#checkContentUriPermissionFull(Uri, int, int, int)
+43 −2
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Intent;
import android.net.Uri;
import android.os.BadParcelableException;
import android.os.IBinder;
import android.os.UserHandle;
import android.util.ArraySet;
@@ -43,6 +44,7 @@ import com.android.server.uri.GrantUri;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.WeakHashMap;

/**
@@ -143,8 +145,8 @@ final class ActivityCallerState {
        final boolean writeMet = callerInfo.mWritableContentUris.contains(grantUri);

        if (!readMet && !writeMet) {
            throw new IllegalArgumentException("The supplied URI wasn't passed at launch: "
                    + grantUri.uri.toSafeString());
            throw new IllegalArgumentException("The supplied URI wasn't passed at launch in"
                    + " #getData, #EXTRA_STREAM, nor #getClipData: " + grantUri.uri.toSafeString());
        }

        final boolean checkRead = (modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0;
@@ -184,6 +186,18 @@ final class ActivityCallerState {
        // getData
        addUriIfContentUri(intent.getData(), uris);

        // EXTRA_STREAM
        if (intent.hasExtra(Intent.EXTRA_STREAM)) {
            final ArrayList<Uri> streams = tryToUnparcelArrayListExtraStreamsUri(intent);
            if (streams == null) {
                addUriIfContentUri(tryToUnparcelExtraStreamUri(intent), uris);
            } else {
                for (int i = streams.size() - 1; i >= 0; i--) {
                    addUriIfContentUri(streams.get(i), uris);
                }
            }
        }

        final ClipData clipData = intent.getClipData();
        if (clipData == null) return uris;

@@ -199,6 +213,33 @@ final class ActivityCallerState {
        return uris;
    }

    private static Uri tryToUnparcelExtraStreamUri(Intent intent) {
        try {
            return intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri.class);
        } catch (BadParcelableException e) {
            // Even though the system "defuses" all the parsed Bundles, i.e. suppresses and logs
            // instances of {@link BadParcelableException}, we still want to be on the safer side
            // and catch the exception to ensure no breakages happen. If the unparcel fails, the
            // item is still preserved with the underlying parcel.
            Slog.w(TAG, "Failed to unparcel an URI in EXTRA_STREAM, returning null: " + e);
            return null;
        }
    }

    private static ArrayList<Uri> tryToUnparcelArrayListExtraStreamsUri(Intent intent) {
        try {
            return intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM, Uri.class);
        } catch (BadParcelableException e) {
            // Even though the system "defuses" all the parsed Bundles, i.e. suppresses and logs
            // instances of {@link BadParcelableException}, we still want to be on the safer side
            // and catch the exception to ensure no breakages happen. If the unparcel fails, the
            // item is still preserved with the underlying parcel.
            Slog.w(TAG, "Failed to unparcel an ArrayList of URIs in EXTRA_STREAM, returning null: "
                    + e);
            return null;
        }
    }

    private static void addUriIfContentUri(Uri uri, ArraySet<Uri> uris) {
        if (uri != null && ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
            uris.add(uri);