summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Bernardo Rufino <brufino@google.com> 2021-09-30 11:17:28 +0000
committer Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> 2021-09-30 11:17:28 +0000
commit4da29a66bef9e19db17e48e08a1834802a7cea4c (patch)
tree67021206cd3058ec5efde14a6a18ba9815f984d9
parentba16e6ed9d70834ab32b62012a9773dd5baded07 (diff)
parent18e5be7b9871663f2fa7b437b004ac4ee5640fc7 (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.java2
-rw-r--r--core/java/android/os/Parcel.java2
-rw-r--r--core/tests/coretests/src/android/os/BundleTest.java205
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];
+ }
+ };
+ }
}