diff options
| author | 2019-02-08 17:25:01 -0800 | |
|---|---|---|
| committer | 2019-02-11 09:12:24 -0800 | |
| commit | 5ca09e9d0dcba2be2afd9de561fdb858df7e788d (patch) | |
| tree | 4effc1d99883b9e070d1edd3c634c782d870bacc | |
| parent | 26835f0b47f8a8ef1ed88553ffeb4e526b183632 (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.java | 32 |
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 |