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

Commit 9e26212d authored by Bernardo Rufino's avatar Bernardo Rufino
Browse files

Avoid full unparcelling where possible in Bundle

and put a warning where it's not possible. This is to make sure we know
when to touch bundles provided by apps.

In this CL:
* deepCopy() now doesn't deserialize lazy objects before copying. It
  doesn't copy them either, it merely passes them into the new map as
  the same reference. This works because we implemented fine-grained
  locking into each lazy value, so concurrent access won't be a problem.
  Furthermore, LazyValue caches the deserialized object, so we'd still
  honor the contract of deepCopy() that "Other types of objects (such
  as Parcelable or Serializable) are referenced as-is and not copied in
  any way". I had to perform one extra check in the synchronized block
  in LazyValue to guarantee this (double-checked locking), I explain
  that in the comments.
* Removed filterValues() and codepaths that used it. This was created
  with the purpose of removing items whose classes weren't available to
  the system to prevent crashes coming from full deserialization. This
  is not a concern anymore with lazy bundle, hence we can remove the
  codepaths altogether (see email for more details).
* Put warnings in javadoc of getMap() and PeristableBundle().

Test: Boots
Test: atest -d android.os.cts.ParcelTest android.os.cts.BundleTest android.os.BundleTest android.os.ParcelTest
Bug: 195622897
Change-Id: I14bb6a7874814f42cbcc6b5fd372c42752aa74c8
parent d3199a60
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -3724,7 +3724,6 @@ public final class ActivityThread extends ClientTransactionHandler {
                        Intent intent = new Intent(activityIntent);
                        intent.setFlags(intent.getFlags() & ~(Intent.FLAG_GRANT_WRITE_URI_PERMISSION
                                | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION));
                        intent.removeUnsafeExtras();
                        content.setDefaultIntent(intent);
                    }
                } else {
+0 −10
Original line number Diff line number Diff line
@@ -8567,16 +8567,6 @@ public class Intent implements Parcelable, Cloneable {
                : null;
    }

    /**
     * Filter extras to only basic types.
     * @hide
     */
    public void removeUnsafeExtras() {
        if (mExtras != null) {
            mExtras = mExtras.filterValues();
        }
    }

    /**
     * @return Whether {@link #maybeStripForHistory} will return an lightened intent or
     * return itself as-is.
+12 −4
Original line number Diff line number Diff line
@@ -376,8 +376,16 @@ public class BaseBundle {
        }
    }

    /** @hide */
    ArrayMap<String, Object> getMap() {
    /**
     * Returns the backing map of this bundle after deserializing every item.
     *
     * <p><b>Warning:</b> This method will deserialize every item on the bundle, including custom
     * types such as {@link Parcelable} and {@link Serializable}, so only use this when you trust
     * the source. Specifically don't use this method on app-provided bundles.
     *
     * @hide
     */
    ArrayMap<String, Object> getItemwiseMap() {
        unparcel(/* itemwise */ true);
        return mMap;
    }
@@ -500,7 +508,7 @@ public class BaseBundle {
                    final int N = fromMap.size();
                    mMap = new ArrayMap<>(N);
                    for (int i = 0; i < N; i++) {
                        mMap.append(fromMap.keyAt(i), deepCopyValue(from.getValueAt(i)));
                        mMap.append(fromMap.keyAt(i), deepCopyValue(fromMap.valueAt(i)));
                    }
                }
            } else {
@@ -1772,7 +1780,7 @@ public class BaseBundle {
            pw.println("[null]");
            return;
        }
        final ArrayMap<String, Object> map = bundle.getMap();
        final ArrayMap<String, Object> map = bundle.getItemwiseMap();
        for (int i = 0; i < map.size(); i++) {
            dumpStats(pw, map.keyAt(i), map.valueAt(i));
        }
+0 −50
Original line number Diff line number Diff line
@@ -347,56 +347,6 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
        return (mFlags & FLAG_HAS_FDS) != 0;
    }

    /**
     * Filter values in Bundle to only basic types.
     * @hide
     */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    public Bundle filterValues() {
        unparcel(/* itemwise */ true);
        Bundle bundle = this;
        if (mMap != null) {
            ArrayMap<String, Object> map = mMap;
            for (int i = map.size() - 1; i >= 0; i--) {
                Object value = map.valueAt(i);
                if (PersistableBundle.isValidType(value)) {
                    continue;
                }
                if (value instanceof Bundle) {
                    Bundle newBundle = ((Bundle)value).filterValues();
                    if (newBundle != value) {
                        if (map == mMap) {
                            // The filter had to generate a new bundle, but we have not yet
                            // created a new one here.  Do that now.
                            bundle = new Bundle(this);
                            // Note the ArrayMap<> constructor is guaranteed to generate
                            // a new object with items in the same order as the original.
                            map = bundle.mMap;
                        }
                        // Replace this current entry with the new child bundle.
                        map.setValueAt(i, newBundle);
                    }
                    continue;
                }
                if (value.getClass().getName().startsWith("android.")) {
                    continue;
                }
                if (map == mMap) {
                    // This is the first time we have had to remove something, that means we
                    // need to switch to a new Bundle.
                    bundle = new Bundle(this);
                    // Note the ArrayMap<> constructor is guaranteed to generate
                    // a new object with items in the same order as the original.
                    map = bundle.mMap;
                }
                map.removeAt(i);
            }
        }
        mFlags |= FLAG_HAS_FDS_KNOWN;
        mFlags &= ~FLAG_HAS_FDS;
        return bundle;
    }

    /** {@hide} */
    @Override
    public void putObject(@Nullable String key, @Nullable Object value) {
+10 −7
Original line number Diff line number Diff line
@@ -3470,6 +3470,8 @@ public final class Parcel {
            Parcel source = mSource;
            if (source != null) {
                synchronized (source) {
                    // Check mSource != null guarantees callers won't ever see different objects.
                    if (mSource != null) {
                        int restore = source.dataPosition();
                        try {
                            source.setDataPosition(mPosition);
@@ -3480,6 +3482,7 @@ public final class Parcel {
                        mSource = null;
                    }
                }
            }
            return mObject;
        }

Loading