summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Garfield Tan <xutan@google.com> 2019-02-08 17:25:01 -0800
committer Garfield Tan <xutan@google.com> 2019-02-11 09:12:24 -0800
commit5ca09e9d0dcba2be2afd9de561fdb858df7e788d (patch)
tree4effc1d99883b9e070d1edd3c634c782d870bacc
parent26835f0b47f8a8ef1ed88553ffeb4e526b183632 (diff)
Clear spiedInstance field for spyOn objects.
All spyOn instances are directly returned as the mock, and put in the mock map with a strong ref in the value of the map. Due to the strong ref in the value the mock map won't purge that item. Note this is not a complete solution, for the same reason as its parent commit. MockCreationListner is registered to a ThreadLocal, so we can only track mocks created in the same thread where it's registered. That includes all befores and afters, but we basically lose all mocks created in test cases because they're run with timeout in a different thread. They are mostly ActivityRecords. Bug: 123984854 Test: Smaller memory pressure shown in mem dump. Change-Id: If3c488a23ab9c59a63d9844fc995e4bb0313896a
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java32
1 files changed, 32 insertions, 0 deletions
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java b/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java
index ef955fb10264..1ce463bbbd9e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java
+++ b/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java
@@ -20,9 +20,11 @@ import android.util.Log;
import org.mockito.Mockito;
import org.mockito.MockitoFramework;
+import org.mockito.internal.creation.settings.CreationSettings;
import org.mockito.listeners.MockCreationListener;
import org.mockito.mock.MockCreationSettings;
+import java.lang.reflect.Field;
import java.util.IdentityHashMap;
/**
@@ -33,6 +35,17 @@ import java.util.IdentityHashMap;
public class MockTracker implements MockCreationListener, AutoCloseable {
private static final String TAG = "MockTracker";
+ private static final Field SPIED_INSTANCE_FIELD;
+
+ static {
+ try {
+ SPIED_INSTANCE_FIELD = CreationSettings.class.getDeclaredField("spiedInstance");
+ SPIED_INSTANCE_FIELD.setAccessible(true);
+ } catch (NoSuchFieldException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
private final MockitoFramework mMockitoFramework = Mockito.framework();
private final IdentityHashMap<Object, Void> mMocks = new IdentityHashMap<>();
@@ -44,6 +57,25 @@ public class MockTracker implements MockCreationListener, AutoCloseable {
@Override
public void onMockCreated(Object mock, MockCreationSettings settings) {
mMocks.put(mock, null);
+ clearSpiedInstanceIfNeeded(mock, settings);
+ }
+
+ // HACK: Changing Mockito core implementation details.
+ // TODO(b/123984854): Remove this once there is a real fix.
+ private void clearSpiedInstanceIfNeeded(Object mock, MockCreationSettings settings) {
+ if (mock != settings.getSpiedInstance()) {
+ // Not a spyOn instance.
+ return;
+ }
+ if (!(settings instanceof CreationSettings)) {
+ throw new IllegalStateException("Unexpected type of settings: " + settings.getClass());
+ }
+ try {
+ SPIED_INSTANCE_FIELD.set(settings, null);
+ Log.d(TAG, "Setting spiedInstance for " + mock + " to null.");
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
}
@Override