Merge changes If3c488a2,Iab08c4a3

* changes:
  Clear spiedInstance field for spyOn objects.
  Track and reset mock to avoid mem leaks.
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index e27dd94..21a4e84 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -72,8 +72,10 @@
 import com.android.server.appop.AppOpsService;
 import com.android.server.firewall.IntentFirewall;
 import com.android.server.uri.UriGrantsManagerInternal;
+import com.android.server.wm.utils.MockTracker;
 
 import org.junit.After;
+import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Rule;
@@ -88,6 +90,8 @@
 class ActivityTestsBase {
     private static int sNextDisplayId = DEFAULT_DISPLAY + 1;
 
+    private static MockTracker sMockTracker;
+
     @Rule
     public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
             new DexmakerShareClassLoaderRule();
@@ -107,9 +111,17 @@
 
     @BeforeClass
     public static void setUpOnceBase() {
+        sMockTracker = new MockTracker();
+
         AttributeCache.init(getInstrumentation().getTargetContext());
     }
 
+    @AfterClass
+    public static void tearDownOnceBase() {
+        sMockTracker.close();
+        sMockTracker = null;
+    }
+
     @Before
     public void setUpBase() {
         mTestInjector.setUp();
@@ -657,12 +669,11 @@
     private static WindowManagerService sMockWindowManagerService;
 
     private static WindowManagerService prepareMockWindowManager() {
-        if (sMockWindowManagerService != null) {
-            return sMockWindowManagerService;
+        if (sMockWindowManagerService == null) {
+            sMockWindowManagerService = mock(WindowManagerService.class);
         }
 
-        final WindowManagerService service = mock(WindowManagerService.class);
-        service.mRoot = mock(RootWindowContainer.class);
+        sMockWindowManagerService.mRoot = mock(RootWindowContainer.class);
 
         doAnswer((InvocationOnMock invocationOnMock) -> {
             final Runnable runnable = invocationOnMock.<Runnable>getArgument(0);
@@ -670,10 +681,9 @@
                 runnable.run();
             }
             return null;
-        }).when(service).inSurfaceTransaction(any());
+        }).when(sMockWindowManagerService).inSurfaceTransaction(any());
 
-        sMockWindowManagerService = service;
-        return service;
+        return sMockWindowManagerService;
     }
 
     /**
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index 67ee4ad..94def2b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -67,6 +67,7 @@
 import org.junit.Test;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -142,7 +143,8 @@
 
     private static void ensureStackPlacement(ActivityStack stack, TaskRecord... tasks) {
         final ArrayList<TaskRecord> stackTasks = stack.getAllTasks();
-        assertEquals(stackTasks.size(), tasks != null ? tasks.length : 0);
+        assertEquals("Expecting " + Arrays.deepToString(tasks) + " got " + stackTasks,
+                stackTasks.size(), tasks != null ? tasks.length : 0);
 
         if (tasks == null) {
             return;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
index b151fb7..1c1fe29 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
@@ -88,6 +88,7 @@
         sPolicy = null;
 
         sMockitoSession.finishMocking();
+        sMockitoSession = null;
     }
 
     private static void setUpTestWindowService() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 3cb2814..a83bf2a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -50,6 +50,7 @@
 import android.view.WindowManager;
 
 import com.android.server.AttributeCache;
+import com.android.server.wm.utils.MockTracker;
 
 import org.junit.After;
 import org.junit.AfterClass;
@@ -77,6 +78,8 @@
     private static int sNextDisplayId = DEFAULT_DISPLAY + 1;
     static int sNextStackId = 1000;
 
+    private static MockTracker sMockTracker;
+
     /** Non-default display. */
     DisplayContent mDisplayContent;
     DisplayInfo mDisplayInfo = new DisplayInfo();
@@ -109,11 +112,18 @@
 
         TestSystemServices.setUpWindowManagerService();
 
+        // MockTracker needs to be initialized after TestSystemServices because we don't want to
+        // track static mocks.
+        sMockTracker = new MockTracker();
+
         sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
     }
 
     @AfterClass
-    public static void tearDonwOnceBase() {
+    public static void tearDownOnceBase() {
+        sMockTracker.close();
+        sMockTracker = null;
+
         TestSystemServices.tearDownWindowManagerService();
     }
 
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
new file mode 100644
index 0000000..1ce463b
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/utils/MockTracker.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.utils;
+
+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;
+
+/**
+ * An util class used to track mock creation, and reset them when closing. Note only one instance is
+ * allowed at anytime, as Mockito framework throws exception if there is already a listener of the
+ * same type registered.
+ */
+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<>();
+
+    public MockTracker() {
+        mMockitoFramework.addListener(this);
+    }
+
+    @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
+    public void close() {
+        mMockitoFramework.removeListener(this);
+
+        for (final Object mock : mMocks.keySet()) {
+            try {
+                Mockito.reset(mock);
+            } catch (Exception e) {
+                Log.e(TAG, "Failed to reset " + mock, e);
+            }
+        }
+        mMocks.clear();
+    }
+}