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

Commit fe1997fc authored by Liana Kazanova (xWF)'s avatar Liana Kazanova (xWF) Committed by Android (Google) Code Review
Browse files

Merge "Revert "Create token for all nested intents of a top level intent."" into main

parents 66883bf0 8115615c
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -398,7 +398,6 @@ public class ClipData implements Parcelable {
         * Retrieve the raw Intent contained in this Item.
         */
        public Intent getIntent() {
            Intent.maybeMarkAsMissingCreatorToken(mIntent);
            return mIntent;
        }

+32 −258
Original line number Diff line number Diff line
@@ -87,7 +87,6 @@ import android.util.AttributeSet;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.XmlUtils;
import com.android.modules.expresslog.Counter;
@@ -109,7 +108,6 @@ import java.util.Locale;
import java.util.Objects;
import java.util.Set;
import java.util.TimeZone;
import java.util.function.Consumer;
/**
 * An intent is an abstract description of an operation to be performed.  It
@@ -894,20 +892,6 @@ public class Intent implements Parcelable, Cloneable {
    public static void maybeMarkAsMissingCreatorToken(Object object) {
        if (object instanceof Intent intent) {
            maybeMarkAsMissingCreatorTokenInternal(intent);
        } else if (object instanceof Parcelable[] parcelables) {
            for (Parcelable p : parcelables) {
                if (p instanceof Intent intent) {
                    maybeMarkAsMissingCreatorTokenInternal(intent);
                }
            }
        } else if (object instanceof ArrayList parcelables) {
            int N = parcelables.size();
            for (int i = 0; i < N; i++) {
                Object p = parcelables.get(i);
                if (p instanceof Intent intent) {
                    maybeMarkAsMissingCreatorTokenInternal(intent);
                }
            }
        }
    }
@@ -12220,70 +12204,7 @@ public class Intent implements Parcelable, Cloneable {
        // Stores a creator token for an intent embedded as an extra intent in a top level intent,
        private IBinder mCreatorToken;
        // Stores all extra keys whose values are intents for a top level intent.
        private ArraySet<NestedIntentKey> mNestedIntentKeys;
    }
    /**
     * @hide
     */
    public static class NestedIntentKey {
        /** @hide */
        @IntDef(flag = true, prefix = {"NESTED_INTENT_KEY_TYPE"}, value = {
                NESTED_INTENT_KEY_TYPE_EXTRA_PARCEL,
                NESTED_INTENT_KEY_TYPE_EXTRA_PARCEL_ARRAY,
                NESTED_INTENT_KEY_TYPE_EXTRA_PARCEL_LIST,
                NESTED_INTENT_KEY_TYPE_CLIP_DATA,
        })
        @Retention(RetentionPolicy.SOURCE)
        private @interface NestedIntentKeyType {
        }
        /**
         * This flag indicates the key is for an extra parcel in mExtras.
         */
        private static final int NESTED_INTENT_KEY_TYPE_EXTRA_PARCEL = 1 << 0;
        /**
         * This flag indicates the key is for an extra parcel array in mExtras and the index is the
         * index of that array.
         */
        private static final int NESTED_INTENT_KEY_TYPE_EXTRA_PARCEL_ARRAY = 1 << 1;
        /**
         * This flag indicates the key is for an extra parcel list in mExtras and the index is the
         * index of that list.
         */
        private static final int NESTED_INTENT_KEY_TYPE_EXTRA_PARCEL_LIST = 1 << 2;
        /**
         * This flag indicates the key is for an extra parcel in mClipData.mItems.
         */
        private static final int NESTED_INTENT_KEY_TYPE_CLIP_DATA = 1 << 3;
        // type can be a short or even byte. But then probably cannot use @IntDef?? Also not sure
        // if it is necessary.
        private final @NestedIntentKeyType int mType;
        private final String mKey;
        private final int mIndex;
        private NestedIntentKey(@NestedIntentKeyType int type, String key, int index) {
            this.mType = type;
            this.mKey = key;
            this.mIndex = index;
        }
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            NestedIntentKey that = (NestedIntentKey) o;
            return mType == that.mType && mIndex == that.mIndex && Objects.equals(mKey, that.mKey);
        }
        @Override
        public int hashCode() {
            return Objects.hash(mType, mKey, mIndex);
        }
        private ArraySet<String> mExtraIntentKeys;
    }
    private @Nullable CreatorTokenInfo mCreatorTokenInfo;
@@ -12306,9 +12227,8 @@ public class Intent implements Parcelable, Cloneable {
    }
    /** @hide */
    @VisibleForTesting
    public Set<NestedIntentKey> getExtraIntentKeys() {
        return mCreatorTokenInfo == null ? null : mCreatorTokenInfo.mNestedIntentKeys;
    public Set<String> getExtraIntentKeys() {
        return mCreatorTokenInfo == null ? null : mCreatorTokenInfo.mExtraIntentKeys;
    }
    /** @hide */
@@ -12326,168 +12246,45 @@ public class Intent implements Parcelable, Cloneable {
     * @hide
     */
    public void collectExtraIntentKeys() {
        if (preventIntentRedirect()) {
            collectNestedIntentKeysRecur(new ArraySet<>());
        }
    }
        if (!preventIntentRedirect()) return;
    private void collectNestedIntentKeysRecur(Set<Intent> visited) {
        if (mExtras != null && !mExtras.isParcelled() && !mExtras.isEmpty()) {
        if (mExtras != null && !mExtras.isEmpty()) {
            for (String key : mExtras.keySet()) {
                Object value = mExtras.get(key);
                if (value instanceof Intent intent && !visited.contains(intent)) {
                    handleNestedIntent(intent, visited, new NestedIntentKey(
                            NestedIntentKey.NESTED_INTENT_KEY_TYPE_EXTRA_PARCEL, key, 0));
                } else if (value instanceof Parcelable[] parcelables) {
                    handleParcelableArray(parcelables, key, visited);
                } else if (value instanceof ArrayList<?> parcelables) {
                    handleParcelableList(parcelables, key, visited);
                }
            }
        }
        if (mClipData != null) {
            for (int i = 0; i < mClipData.getItemCount(); i++) {
                Intent intent = mClipData.getItemAt(i).mIntent;
                if (intent != null && !visited.contains(intent)) {
                    handleNestedIntent(intent, visited, new NestedIntentKey(
                            NestedIntentKey.NESTED_INTENT_KEY_TYPE_CLIP_DATA, null, i));
                }
            }
        }
    }
    private void handleNestedIntent(Intent intent, Set<Intent> visited, NestedIntentKey key) {
        visited.add(intent);
                if (mExtras.get(key) instanceof Intent) {
                    if (mCreatorTokenInfo == null) {
                        mCreatorTokenInfo = new CreatorTokenInfo();
                    }
        if (mCreatorTokenInfo.mNestedIntentKeys == null) {
            mCreatorTokenInfo.mNestedIntentKeys = new ArraySet<>();
                    if (mCreatorTokenInfo.mExtraIntentKeys == null) {
                        mCreatorTokenInfo.mExtraIntentKeys = new ArraySet<>();
                    }
        mCreatorTokenInfo.mNestedIntentKeys.add(key);
        intent.collectNestedIntentKeysRecur(visited);
                    mCreatorTokenInfo.mExtraIntentKeys.add(key);
                }
    private void handleParcelableArray(Parcelable[] parcelables, String key, Set<Intent> visited) {
        for (int i = 0; i < parcelables.length; i++) {
            if (parcelables[i] instanceof Intent intent && !visited.contains(intent)) {
                handleNestedIntent(intent, visited, new NestedIntentKey(
                        NestedIntentKey.NESTED_INTENT_KEY_TYPE_EXTRA_PARCEL_ARRAY, key, i));
            }
        }
    }
    private void handleParcelableList(ArrayList<?> parcelables, String key, Set<Intent> visited) {
        for (int i = 0; i < parcelables.size(); i++) {
            if (parcelables.get(i) instanceof Intent intent && !visited.contains(intent)) {
                handleNestedIntent(intent, visited, new NestedIntentKey(
                        NestedIntentKey.NESTED_INTENT_KEY_TYPE_EXTRA_PARCEL_LIST, key, i));
    /** @hide */
    public void checkCreatorToken() {
        if (mExtras == null) return;
        if (mCreatorTokenInfo != null && mCreatorTokenInfo.mExtraIntentKeys != null) {
            for (String key : mCreatorTokenInfo.mExtraIntentKeys) {
                try {
                    Intent extraIntent = mExtras.getParcelable(key, Intent.class);
                    if (extraIntent == null) {
                        Log.w(TAG, "The key {" + key
                                + "} does not correspond to an intent in the bundle.");
                        continue;
                    }
                    extraIntent.mLocalFlags |= LOCAL_FLAG_TRUSTED_CREATOR_TOKEN_PRESENT;
                } catch (Exception e) {
                    Log.e(TAG, "Failed to validate creator token. key: " + key + ".", e);
                }
            }
    private static final Consumer<Intent> CHECK_CREATOR_TOKEN_ACTION = intent -> {
        intent.mLocalFlags |= LOCAL_FLAG_TRUSTED_CREATOR_TOKEN_PRESENT;
        if (intent.mExtras != null) {
            intent.mExtras.enableTokenVerification();
        }
    };
    /** @hide */
    public void checkCreatorToken() {
        forEachNestedCreatorToken(CHECK_CREATOR_TOKEN_ACTION);
        if (mExtras != null) {
        // mark the bundle as intent extras after calls to getParcelable.
        // otherwise, the logic to mark missing token would run before
        // mark trusted creator token present.
            mExtras.enableTokenVerification();
        }
    }
    /** @hide */
    public void forEachNestedCreatorToken(Consumer<? super Intent> action) {
        if (mExtras == null && mClipData == null) return;
        if (mCreatorTokenInfo != null && mCreatorTokenInfo.mNestedIntentKeys != null) {
            int N = mCreatorTokenInfo.mNestedIntentKeys.size();
            for (int i = 0; i < N; i++) {
                NestedIntentKey key = mCreatorTokenInfo.mNestedIntentKeys.valueAt(i);
                Intent extraIntent = extractIntentFromKey(key);
                if (extraIntent != null) {
                    action.accept(extraIntent);
                    extraIntent.forEachNestedCreatorToken(action);
                } else {
                    Log.w(TAG, getLogMessageForKey(key));
                }
            }
        }
    }
    private Intent extractIntentFromKey(NestedIntentKey key) {
        switch (key.mType) {
            case NestedIntentKey.NESTED_INTENT_KEY_TYPE_EXTRA_PARCEL:
                return mExtras == null ? null : mExtras.getParcelable(key.mKey, Intent.class);
            case NestedIntentKey.NESTED_INTENT_KEY_TYPE_EXTRA_PARCEL_ARRAY:
                if (mExtras == null) return null;
                Intent[] extraIntents = mExtras.getParcelableArray(key.mKey, Intent.class);
                if (extraIntents != null && key.mIndex < extraIntents.length) {
                    return extraIntents[key.mIndex];
                }
                break;
            case NestedIntentKey.NESTED_INTENT_KEY_TYPE_EXTRA_PARCEL_LIST:
                if (mExtras == null) return null;
                ArrayList<Intent> extraIntentsList = mExtras.getParcelableArrayList(key.mKey,
                        Intent.class);
                if (extraIntentsList != null && key.mIndex < extraIntentsList.size()) {
                    return extraIntentsList.get(key.mIndex);
                }
                break;
            case NestedIntentKey.NESTED_INTENT_KEY_TYPE_CLIP_DATA:
                if (mClipData == null) return null;
                if (key.mIndex < mClipData.getItemCount()) {
                    ClipData.Item item = mClipData.getItemAt(key.mIndex);
                    if (item != null) {
                        return item.mIntent;
                    }
                }
                break;
        }
        return null;
    }
    private String getLogMessageForKey(NestedIntentKey key) {
        switch (key.mType) {
            case NestedIntentKey.NESTED_INTENT_KEY_TYPE_EXTRA_PARCEL:
                return "The key {" + key + "} does not correspond to an intent in the bundle.";
            case NestedIntentKey.NESTED_INTENT_KEY_TYPE_EXTRA_PARCEL_ARRAY:
                if (mExtras.getParcelableArray(key.mKey, Intent.class) == null) {
                    return "The key {" + key
                            + "} does not correspond to a Parcelable[] in the bundle.";
                } else {
                    return "Parcelable[" + key.mIndex + "] for key {" + key + "} is not an intent.";
                }
            case NestedIntentKey.NESTED_INTENT_KEY_TYPE_EXTRA_PARCEL_LIST:
                if (mExtras.getParcelableArrayList(key.mKey, Intent.class) == null) {
                    return "The key {" + key
                            + "} does not correspond to an ArrayList<Parcelable> in the bundle.";
                } else {
                    return "List.get(" + key.mIndex + ") for key {" + key + "} is not an intent.";
                }
            case NestedIntentKey.NESTED_INTENT_KEY_TYPE_CLIP_DATA:
                if (key.mIndex >= mClipData.getItemCount()) {
                    return "Index out of range for clipData items. index: " + key.mIndex
                            + ". item counts: " + mClipData.getItemCount();
                } else {
                    return "clipData items at index [" + key.mIndex
                            + "] is null or does not contain an intent.";
                }
            default:
                return "Unknown key type: " + key.mType;
        }
        mExtras.setIsIntentExtra();
    }
    /**
@@ -12560,19 +12357,7 @@ public class Intent implements Parcelable, Cloneable {
            } else {
                out.writeInt(1);
                out.writeStrongBinder(mCreatorTokenInfo.mCreatorToken);
                if (mCreatorTokenInfo.mNestedIntentKeys != null) {
                    final int N = mCreatorTokenInfo.mNestedIntentKeys.size();
                    out.writeInt(N);
                    for (int i = 0; i < N; i++) {
                        NestedIntentKey key = mCreatorTokenInfo.mNestedIntentKeys.valueAt(i);
                        out.writeInt(key.mType);
                        out.writeString8(key.mKey);
                        out.writeInt(key.mIndex);
                    }
                } else {
                    out.writeInt(0);
                }
                out.writeArraySet(mCreatorTokenInfo.mExtraIntentKeys);
            }
        }
    }
@@ -12637,18 +12422,7 @@ public class Intent implements Parcelable, Cloneable {
            if (in.readInt() != 0) {
                mCreatorTokenInfo = new CreatorTokenInfo();
                mCreatorTokenInfo.mCreatorToken = in.readStrongBinder();
                N = in.readInt();
                if (N > 0) {
                    mCreatorTokenInfo.mNestedIntentKeys = new ArraySet<>(N);
                    for (int i = 0; i < N; i++) {
                        int type = in.readInt();
                        String key = in.readString8();
                        int index = in.readInt();
                        mCreatorTokenInfo.mNestedIntentKeys.append(
                                new NestedIntentKey(type, key, index));
                    }
                }
                mCreatorTokenInfo.mExtraIntentKeys = (ArraySet<String>) in.readArraySet(null);
            }
        }
    }
+1 −1
Original line number Diff line number Diff line
@@ -281,7 +281,7 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
    }

    /** {@hide} */
    public void enableTokenVerification() {
    public void setIsIntentExtra() {
        mFlags |= FLAG_VERIFY_TOKENS_PRESENT;
    }

+5 −38
Original line number Diff line number Diff line
@@ -37,10 +37,6 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 *  Build/Install/Run:
 *   atest FrameworksCoreTests:IntentTest
@@ -61,12 +57,7 @@ public class IntentTest {
    public void testReadFromParcelWithExtraIntentKeys() {
        Intent intent = new Intent("TEST_ACTION");
        intent.putExtra(TEST_EXTRA_NAME, new Intent(TEST_ACTION));
        // Not an intent, don't count.
        intent.putExtra(TEST_EXTRA_NAME + "2", 1);
        ArrayList<Intent> intents = new ArrayList<>();
        intents.add(new Intent(TEST_ACTION));
        intent.putParcelableArrayListExtra(TEST_EXTRA_NAME + "3", intents);
        intent.setClipData(ClipData.newIntent("label", new Intent(TEST_ACTION)));

        intent.collectExtraIntentKeys();
        final Parcel parcel = Parcel.obtain();
@@ -77,7 +68,7 @@ public class IntentTest {

        assertEquals(intent.getAction(), target.getAction());
        assertEquals(intent.getExtraIntentKeys(), target.getExtraIntentKeys());
        assertThat(intent.getExtraIntentKeys()).hasSize(3);
        assertThat(intent.getExtraIntentKeys()).hasSize(1);
    }

    @Test
@@ -96,37 +87,13 @@ public class IntentTest {
    @RequiresFlagsEnabled(Flags.FLAG_PREVENT_INTENT_REDIRECT)
    public void testCollectExtraIntentKeys() {
        Intent intent = new Intent(TEST_ACTION);

        Intent[] intents = new Intent[10];
        for (int i = 0; i < intents.length; i++) {
            intents[i] = new Intent("action" + i);
        }
        Intent[] intents2 = new Intent[2]; // intents[6-7]
        System.arraycopy(intents, 6, intents2, 0, intents2.length);
        ArrayList<Intent> intents3 = new ArrayList<>(2);
        intents3.addAll(Arrays.asList(intents).subList(8, 10)); // intents[8-9]
        intent.putExtra("key1", intents[0]);
        intent.putExtra("array-key", intents2);
        intent.setClipData(ClipData.newIntent("label2", intents[1]));
        intent.putExtra("intkey", 1);
        intents[0].putExtra("key3", intents[2]);
        intents[0].setClipData(ClipData.newIntent("label4", intents[3]));
        intents[0].putParcelableArrayListExtra("array-list-key", intents3);
        intents[1].putExtra("key3", intents[4]);
        intents[1].setClipData(ClipData.newIntent("label4", intents[5]));
        intents[5].putExtra("intkey", 2);
        Intent extraIntent = new Intent(TEST_ACTION, TEST_URI);
        intent.putExtra(TEST_EXTRA_NAME, extraIntent);

        intent.collectExtraIntentKeys();

        // collect all actions of nested intents.
        final List<String> actions = new ArrayList<>();
        intent.forEachNestedCreatorToken(intent1 -> {
            actions.add(intent1.getAction());
        });
        assertThat(actions).hasSize(10);
        for (int i = 0; i < intents.length; i++) {
            assertThat(actions).contains("action" + i);
        }
        assertThat(intent.getExtraIntentKeys()).hasSize(1);
        assertThat(intent.getExtraIntentKeys()).contains(TEST_EXTRA_NAME);
    }

}
+24 −11
Original line number Diff line number Diff line
@@ -19307,18 +19307,31 @@ public class ActivityManagerService extends IActivityManager.Stub
    public void addCreatorToken(@Nullable Intent intent, String creatorPackage) {
        if (!preventIntentRedirect()) return;
        if (intent == null) return;
        intent.forEachNestedCreatorToken(extraIntent -> {
            IntentCreatorToken creatorToken = createIntentCreatorToken(extraIntent, creatorPackage);
        if (intent == null || intent.getExtraIntentKeys() == null) return;
        for (String key : intent.getExtraIntentKeys()) {
            try {
                Intent extraIntent = intent.getParcelableExtra(key, Intent.class);
                if (extraIntent == null) {
                    Slog.w(TAG, "The key {" + key
                            + "} does not correspond to an intent in the extra bundle.");
                    continue;
                }
                IntentCreatorToken creatorToken = createIntentCreatorToken(extraIntent,
                        creatorPackage);
                if (creatorToken != null) {
                    extraIntent.setCreatorToken(creatorToken);
                // TODO remove Slog.wtf once proven FrameworkStatsLog works. b/375396329
                    Slog.wtf(TAG, "A creator token is added to an intent. creatorPackage: "
                            + creatorPackage + "; intent: " + intent);
                    FrameworkStatsLog.write(INTENT_CREATOR_TOKEN_ADDED,
                            creatorToken.getCreatorUid());
                }
        });
            } catch (Exception e) {
                Slog.wtf(TAG,
                        "Something went wrong when trying to add creator token for embedded "
                                + "intents of intent: ."
                                + intent, e);
            }
        }
    }
    private IntentCreatorToken createIntentCreatorToken(Intent intent, String creatorPackage) {
Loading