diff options
| author | 2021-09-30 11:17:28 +0000 | |
|---|---|---|
| committer | 2021-09-30 11:17:28 +0000 | |
| commit | 4da29a66bef9e19db17e48e08a1834802a7cea4c (patch) | |
| tree | 67021206cd3058ec5efde14a6a18ba9815f984d9 | |
| parent | ba16e6ed9d70834ab32b62012a9773dd5baded07 (diff) | |
| parent | 18e5be7b9871663f2fa7b437b004ac4ee5640fc7 (diff) | |
Merge "Log.wtf in mismatch + tests" am: 1cdbc7cbd1 am: d60218eb45 am: 5d32036b41 am: 18e5be7b98
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1837194
Change-Id: I97dd9ffe70d442d587759dbdd8fbdc2acc9a029e
| -rw-r--r-- | core/java/android/os/BaseBundle.java | 2 | ||||
| -rw-r--r-- | core/java/android/os/Parcel.java | 2 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/os/BundleTest.java | 205 |
3 files changed, 207 insertions, 2 deletions
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java index fb21ce30415f..64d54b820a92 100644 --- a/core/java/android/os/BaseBundle.java +++ b/core/java/android/os/BaseBundle.java @@ -431,7 +431,7 @@ public class BaseBundle { * * @hide */ - public static boolean kindofEquals(BaseBundle a, BaseBundle b) { + public static boolean kindofEquals(@Nullable BaseBundle a, @Nullable BaseBundle b) { return (a == b) || (a != null && a.kindofEquals(b)); } diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 2be9533e6818..e8e2e6e93622 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -3404,7 +3404,7 @@ public final class Parcel { object = readValue(type, loader); int actual = dataPosition() - start; if (actual != length) { - Log.w(TAG, + Slog.wtfStack(TAG, "Unparcelling of " + object + " of type " + Parcel.valueTypeToString(type) + " consumed " + actual + " bytes, but " + length + " expected."); } diff --git a/core/tests/coretests/src/android/os/BundleTest.java b/core/tests/coretests/src/android/os/BundleTest.java index 4cc70ba6448d..9d2cab3f7026 100644 --- a/core/tests/coretests/src/android/os/BundleTest.java +++ b/core/tests/coretests/src/android/os/BundleTest.java @@ -16,16 +16,24 @@ package android.os; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; +import android.util.Log; + import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import org.junit.After; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.Objects; + /** * Unit tests for bundle that requires accessing hidden APS. Tests that can be written only with * public APIs should go in the CTS counterpart. @@ -35,6 +43,14 @@ import org.junit.runner.RunWith; @SmallTest @RunWith(AndroidJUnit4.class) public class BundleTest { + private Log.TerribleFailureHandler mWtfHandler; + + @After + public void tearDown() throws Exception { + if (mWtfHandler != null) { + Log.setWtfHandler(mWtfHandler); + } + } /** * Take a bundle, write it to a parcel and return the parcel. @@ -217,4 +233,193 @@ public class BundleTest { // return true assertTrue(BaseBundle.kindofEquals(bundle1, bundle2)); } + + @Test + public void kindofEquals_lazyValues() { + Parcelable p1 = new CustomParcelable(13, "Tiramisu"); + Parcelable p2 = new CustomParcelable(13, "Tiramisu"); + + // 2 maps with live objects + Bundle a = new Bundle(); + a.putParcelable("key1", p1); + Bundle b = new Bundle(); + b.putParcelable("key1", p2); + assertTrue(Bundle.kindofEquals(a, b)); + + // 2 identical parcels + a.readFromParcel(getParcelledBundle(a)); + a.setClassLoader(getClass().getClassLoader()); + b.readFromParcel(getParcelledBundle(b)); + b.setClassLoader(getClass().getClassLoader()); + assertTrue(Bundle.kindofEquals(a, b)); + + // 2 lazy values with identical parcels inside + a.isEmpty(); + b.isEmpty(); + assertTrue(Bundle.kindofEquals(a, b)); + + // 1 lazy value vs 1 live object + a.getParcelable("key1"); + assertFalse(Bundle.kindofEquals(a, b)); + + // 2 live objects + b.getParcelable("key1"); + assertTrue(Bundle.kindofEquals(a, b)); + } + + @Test + public void kindofEquals_lazyValuesWithIdenticalParcels_returnsTrue() { + Parcelable p1 = new CustomParcelable(13, "Tiramisu"); + Parcelable p2 = new CustomParcelable(13, "Tiramisu"); + Bundle a = new Bundle(); + a.putParcelable("key", p1); + a.readFromParcel(getParcelledBundle(a)); + a.setClassLoader(getClass().getClassLoader()); + Bundle b = new Bundle(); + b.putParcelable("key", p2); + b.readFromParcel(getParcelledBundle(b)); + b.setClassLoader(getClass().getClassLoader()); + // 2 lazy values with identical parcels inside + a.isEmpty(); + b.isEmpty(); + + assertTrue(Bundle.kindofEquals(a, b)); + } + + @Test + public void kindofEquals_lazyValuesAndDifferentClassLoaders_returnsFalse() { + Parcelable p1 = new CustomParcelable(13, "Tiramisu"); + Parcelable p2 = new CustomParcelable(13, "Tiramisu"); + Bundle a = new Bundle(); + a.putParcelable("key", p1); + a.readFromParcel(getParcelledBundle(a)); + a.setClassLoader(getClass().getClassLoader()); + Bundle b = new Bundle(); + b.putParcelable("key", p2); + b.readFromParcel(getParcelledBundle(b)); + b.setClassLoader(Bundle.class.getClassLoader()); // BCP + // 2 lazy values with identical parcels inside + a.isEmpty(); + b.isEmpty(); + + assertFalse(Bundle.kindofEquals(a, b)); + } + + @Test + public void kindofEquals_lazyValuesOfDifferentTypes_returnsFalse() { + Parcelable p = new CustomParcelable(13, "Tiramisu"); + Parcelable[] ps = {p}; + Bundle a = new Bundle(); + a.putParcelable("key", p); + a.readFromParcel(getParcelledBundle(a)); + a.setClassLoader(getClass().getClassLoader()); + Bundle b = new Bundle(); + b.putParcelableArray("key", ps); + b.readFromParcel(getParcelledBundle(b)); + b.setClassLoader(getClass().getClassLoader()); + a.isEmpty(); + b.isEmpty(); + + assertFalse(Bundle.kindofEquals(a, b)); + } + + @Test + public void kindofEquals_lazyValuesWithDifferentLengths_returnsFalse() { + Parcelable p1 = new CustomParcelable(13, "Tiramisu"); + Parcelable p2 = new CustomParcelable(13, "Tiramisuuuuuuuu"); + Bundle a = new Bundle(); + a.putParcelable("key", p1); + a.readFromParcel(getParcelledBundle(a)); + a.setClassLoader(getClass().getClassLoader()); + Bundle b = new Bundle(); + b.putParcelable("key", p2); + b.readFromParcel(getParcelledBundle(b)); + b.setClassLoader(getClass().getClassLoader()); + a.isEmpty(); + b.isEmpty(); + + assertFalse(Bundle.kindofEquals(a, b)); + } + + @Test + public void readWriteLengthMismatch_logsWtf() throws Exception { + mWtfHandler = Log.setWtfHandler((tag, e, system) -> { + throw new RuntimeException(e); + }); + Parcelable parcelable = new CustomParcelable(13, "Tiramisu").setHasLengthMismatch(true); + Bundle bundle = new Bundle(); + bundle.putParcelable("p", parcelable); + bundle.readFromParcel(getParcelledBundle(bundle)); + bundle.setClassLoader(getClass().getClassLoader()); + RuntimeException e = assertThrows(RuntimeException.class, () -> bundle.getParcelable("p")); + assertThat(e.getCause()).isInstanceOf(Log.TerribleFailure.class); + } + + private static class CustomParcelable implements Parcelable { + public final int integer; + public final String string; + public boolean hasLengthMismatch; + + CustomParcelable(int integer, String string) { + this.integer = integer; + this.string = string; + } + + protected CustomParcelable(Parcel in) { + integer = in.readInt(); + string = in.readString(); + hasLengthMismatch = in.readBoolean(); + } + + public CustomParcelable setHasLengthMismatch(boolean hasLengthMismatch) { + this.hasLengthMismatch = hasLengthMismatch; + return this; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(integer); + out.writeString(string); + out.writeBoolean(hasLengthMismatch); + if (hasLengthMismatch) { + out.writeString("extra-write"); + } + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof CustomParcelable)) { + return false; + } + CustomParcelable + that = (CustomParcelable) other; + return integer == that.integer + && hasLengthMismatch == that.hasLengthMismatch + && string.equals(that.string); + } + + @Override + public int hashCode() { + return Objects.hash(integer, string, hasLengthMismatch); + } + + public static final Creator<CustomParcelable> CREATOR = new Creator<CustomParcelable>() { + @Override + public CustomParcelable createFromParcel(Parcel in) { + return new CustomParcelable(in); + } + @Override + public CustomParcelable[] newArray(int size) { + return new CustomParcelable[size]; + } + }; + } } |