Use singleton WindowManagerService for testing
This CL introduces a single WindowManagerService instance and uses it for all tests that extend WindowTestBase. This way we can decrease the number of object counts in the heap after running 526 presubmit tests in WmTests. Bug: 113239988 Test: Pass all presumit tests in WmTests. $ atest --test-mapping frameworks/base/services/core/java/com/android/server/wm Change-Id: I8e5af477def6207bcc86cace6b240873516d075d
This commit is contained in:
@@ -115,6 +115,10 @@ class ActivityTestsBase {
|
||||
@After
|
||||
public void tearDownBase() {
|
||||
mTestInjector.tearDown();
|
||||
if (mService != null) {
|
||||
mService.setWindowManager(null);
|
||||
mService = null;
|
||||
}
|
||||
}
|
||||
|
||||
ActivityTaskManagerService createActivityTaskManagerService() {
|
||||
@@ -619,7 +623,13 @@ class ActivityTestsBase {
|
||||
}
|
||||
}
|
||||
|
||||
private static WindowManagerService sMockWindowManagerService;
|
||||
|
||||
private static WindowManagerService prepareMockWindowManager() {
|
||||
if (sMockWindowManagerService != null) {
|
||||
return sMockWindowManagerService;
|
||||
}
|
||||
|
||||
final WindowManagerService service = mock(WindowManagerService.class);
|
||||
service.mRoot = mock(RootWindowContainer.class);
|
||||
|
||||
@@ -631,6 +641,7 @@ class ActivityTestsBase {
|
||||
return null;
|
||||
}).when(service).inSurfaceTransaction(any());
|
||||
|
||||
sMockWindowManagerService = service;
|
||||
return service;
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ import com.android.server.statusbar.StatusBarManagerInternal;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
@@ -86,7 +87,7 @@ public class DisplayRotationTests {
|
||||
|
||||
private StatusBarManagerInternal mPreviousStatusBarManagerInternal;
|
||||
|
||||
private WindowManagerService mMockWm;
|
||||
private static WindowManagerService sMockWm;
|
||||
private DisplayContent mMockDisplayContent;
|
||||
private DisplayPolicy mMockDisplayPolicy;
|
||||
private Context mMockContext;
|
||||
@@ -108,13 +109,16 @@ public class DisplayRotationTests {
|
||||
|
||||
private DisplayRotation mTarget;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpOnce() {
|
||||
sMockWm = mock(WindowManagerService.class);
|
||||
sMockWm.mPowerManagerInternal = mock(PowerManagerInternal.class);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
FakeSettingsProvider.clearSettingsProvider();
|
||||
|
||||
mMockWm = mock(WindowManagerService.class);
|
||||
mMockWm.mPowerManagerInternal = mock(PowerManagerInternal.class);
|
||||
|
||||
mPreviousStatusBarManagerInternal = LocalServices.getService(
|
||||
StatusBarManagerInternal.class);
|
||||
LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
|
||||
@@ -452,7 +456,7 @@ public class DisplayRotationTests {
|
||||
mOrientationSensorListener.onSensorChanged(createSensorEvent(Surface.ROTATION_90));
|
||||
assertTrue(waitForUiHandler());
|
||||
|
||||
verify(mMockWm).updateRotation(false, false);
|
||||
verify(sMockWm).updateRotation(false, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -833,8 +837,9 @@ public class DisplayRotationTests {
|
||||
.thenReturn(mFakeSettingsProvider.getIContentProvider());
|
||||
|
||||
mMockDisplayWindowSettings = mock(DisplayWindowSettings.class);
|
||||
mTarget = new DisplayRotation(mMockWm, mMockDisplayContent, mMockDisplayPolicy,
|
||||
mTarget = new DisplayRotation(sMockWm, mMockDisplayContent, mMockDisplayPolicy,
|
||||
mMockDisplayWindowSettings, mMockContext, new Object());
|
||||
reset(sMockWm);
|
||||
|
||||
captureObservers();
|
||||
}
|
||||
|
||||
@@ -34,7 +34,12 @@ import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT;
|
||||
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.isNull;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
|
||||
@@ -47,10 +52,6 @@ import static com.android.server.wm.LockTaskController.STATUS_BAR_MASK_PINNED;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
|
||||
import android.app.StatusBarManager;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
@@ -115,6 +116,7 @@ public class LockTaskControllerTest {
|
||||
|
||||
private LockTaskController mLockTaskController;
|
||||
private Context mContext;
|
||||
private String mPackageName;
|
||||
private String mLockToAppSetting;
|
||||
|
||||
@Before
|
||||
@@ -122,6 +124,7 @@ public class LockTaskControllerTest {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mContext = getInstrumentation().getTargetContext();
|
||||
mPackageName = mContext.getPackageName();
|
||||
mLockToAppSetting = Settings.Secure.getString(mContext.getContentResolver(),
|
||||
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED);
|
||||
|
||||
@@ -146,6 +149,7 @@ public class LockTaskControllerTest {
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
mLockTaskController.setWindowManager(null);
|
||||
Settings.Secure.putString(mContext.getContentResolver(),
|
||||
Settings.Secure.LOCK_TO_APP_EXIT_LOCKED, mLockToAppSetting);
|
||||
}
|
||||
@@ -223,7 +227,7 @@ public class LockTaskControllerTest {
|
||||
// THEN lock task mode should be started
|
||||
verifyLockTaskStarted(STATUS_BAR_MASK_PINNED, DISABLE2_NONE);
|
||||
// THEN screen pinning toast should be shown
|
||||
verify(mStatusBarService).showPinningEnterExitToast(true /* entering */);
|
||||
verify(mStatusBarService).showPinningEnterExitToast(eq(true /* entering */));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -390,9 +394,9 @@ public class LockTaskControllerTest {
|
||||
// THEN lock task mode should have been finished
|
||||
verifyLockTaskStopped(times(1));
|
||||
// THEN the keyguard should be shown
|
||||
verify(mLockPatternUtils).requireCredentialEntry(UserHandle.USER_ALL);
|
||||
verify(mLockPatternUtils).requireCredentialEntry(eq(UserHandle.USER_ALL));
|
||||
// THEN screen pinning toast should be shown
|
||||
verify(mStatusBarService).showPinningEnterExitToast(false /* entering */);
|
||||
verify(mStatusBarService).showPinningEnterExitToast(eq(false /* entering */));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -509,9 +513,9 @@ public class LockTaskControllerTest {
|
||||
& ~DISABLE_HOME;
|
||||
int expectedFlags2 = DISABLE2_MASK;
|
||||
verify(mStatusBarService).disable(eq(expectedFlags), any(IBinder.class),
|
||||
eq(mContext.getPackageName()));
|
||||
eq(mPackageName));
|
||||
verify(mStatusBarService).disable2(eq(expectedFlags2), any(IBinder.class),
|
||||
eq(mContext.getPackageName()));
|
||||
eq(mPackageName));
|
||||
|
||||
// reset invocation counter
|
||||
reset(mStatusBarService);
|
||||
@@ -526,9 +530,9 @@ public class LockTaskControllerTest {
|
||||
expectedFlags2 = DISABLE2_MASK
|
||||
& ~DISABLE2_NOTIFICATION_SHADE;
|
||||
verify(mStatusBarService).disable(eq(expectedFlags), any(IBinder.class),
|
||||
eq(mContext.getPackageName()));
|
||||
eq(mPackageName));
|
||||
verify(mStatusBarService).disable2(eq(expectedFlags2), any(IBinder.class),
|
||||
eq(mContext.getPackageName()));
|
||||
eq(mPackageName));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -548,9 +552,9 @@ public class LockTaskControllerTest {
|
||||
|
||||
// THEN status bar shouldn't change
|
||||
verify(mStatusBarService, never()).disable(anyInt(), any(IBinder.class),
|
||||
eq(mContext.getPackageName()));
|
||||
eq(mPackageName));
|
||||
verify(mStatusBarService, never()).disable2(anyInt(), any(IBinder.class),
|
||||
eq(mContext.getPackageName()));
|
||||
eq(mPackageName));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -657,14 +661,14 @@ public class LockTaskControllerTest {
|
||||
verify(mWindowManager).disableKeyguard(any(IBinder.class), anyString(), eq(TEST_USER_ID));
|
||||
// THEN the status bar should have been disabled
|
||||
verify(mStatusBarService).disable(eq(statusBarMask), any(IBinder.class),
|
||||
eq(mContext.getPackageName()));
|
||||
eq(mPackageName));
|
||||
verify(mStatusBarService).disable2(eq(statusBarMask2), any(IBinder.class),
|
||||
eq(mContext.getPackageName()));
|
||||
eq(mPackageName));
|
||||
// THEN recents should have been notified
|
||||
verify(mRecentTasks).onLockTaskModeStateChanged(anyInt(), eq(TEST_USER_ID));
|
||||
// THEN the DO/PO should be informed about the operation
|
||||
verify(mDevicePolicyManager).notifyLockTaskModeChanged(true, TEST_PACKAGE_NAME,
|
||||
TEST_USER_ID);
|
||||
verify(mDevicePolicyManager).notifyLockTaskModeChanged(eq(true), eq(TEST_PACKAGE_NAME),
|
||||
eq(TEST_USER_ID));
|
||||
}
|
||||
|
||||
private void verifyLockTaskStopped(VerificationMode mode) throws Exception {
|
||||
@@ -672,11 +676,12 @@ public class LockTaskControllerTest {
|
||||
verify(mWindowManager, mode).reenableKeyguard(any(IBinder.class), eq(TEST_USER_ID));
|
||||
// THEN the status bar should have been disabled
|
||||
verify(mStatusBarService, mode).disable(eq(StatusBarManager.DISABLE_NONE),
|
||||
any(IBinder.class), eq(mContext.getPackageName()));
|
||||
any(IBinder.class), eq(mPackageName));
|
||||
verify(mStatusBarService, mode).disable2(eq(StatusBarManager.DISABLE2_NONE),
|
||||
any(IBinder.class), eq(mContext.getPackageName()));
|
||||
any(IBinder.class), eq(mPackageName));
|
||||
// THEN the DO/PO should be informed about the operation
|
||||
verify(mDevicePolicyManager, mode).notifyLockTaskModeChanged(false, null, TEST_USER_ID);
|
||||
verify(mDevicePolicyManager, mode).notifyLockTaskModeChanged(eq(false), isNull(),
|
||||
eq(TEST_USER_ID));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,6 +33,8 @@ import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
|
||||
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
|
||||
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -58,7 +60,6 @@ import android.view.WindowInsets;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import org.junit.After;
|
||||
@@ -80,8 +81,8 @@ import java.util.function.BooleanSupplier;
|
||||
@Presubmit
|
||||
public class ScreenDecorWindowTests {
|
||||
|
||||
private final Context mContext = InstrumentationRegistry.getTargetContext();
|
||||
private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||
private final Context mContext = getInstrumentation().getTargetContext();
|
||||
private final Instrumentation mInstrumentation = getInstrumentation();
|
||||
|
||||
private WindowManager mWm;
|
||||
private ArrayList<View> mWindows = new ArrayList<>();
|
||||
|
||||
@@ -1,242 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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;
|
||||
|
||||
import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.content.Context;
|
||||
import android.hardware.display.DisplayManagerInternal;
|
||||
import android.os.Handler;
|
||||
import android.os.PowerManagerInternal;
|
||||
import android.os.PowerSaveState;
|
||||
import android.view.Display;
|
||||
import android.view.InputChannel;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.SurfaceControl.Transaction;
|
||||
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.input.InputManagerService;
|
||||
import com.android.server.policy.WindowManagerPolicy;
|
||||
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
/**
|
||||
* A test rule that sets up a fresh WindowManagerService instance before each test and makes sure
|
||||
* to properly tear it down after.
|
||||
*
|
||||
* <p>
|
||||
* Usage:
|
||||
* <pre>
|
||||
* {@literal @}Rule
|
||||
* public final WindowManagerServiceRule mWmRule = new WindowManagerServiceRule();
|
||||
* </pre>
|
||||
*/
|
||||
public class WindowManagerServiceRule implements TestRule {
|
||||
|
||||
private WindowManagerService mService;
|
||||
private TestWindowManagerPolicy mPolicy;
|
||||
// Record all {@link SurfaceControl.Transaction} created while testing and releases native
|
||||
// resources when test finishes.
|
||||
private final List<WeakReference<Transaction>> mSurfaceTransactions = new ArrayList<>();
|
||||
// Record all {@link SurfaceControl} created while testing and releases native resources when
|
||||
// test finishes.
|
||||
private final List<WeakReference<SurfaceControl>> mSurfaceControls = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public Statement apply(Statement base, Description description) {
|
||||
return new Statement() {
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
runWithDexmakerShareClassLoader(this::setUp);
|
||||
try {
|
||||
base.evaluate();
|
||||
} finally {
|
||||
tearDown();
|
||||
}
|
||||
}
|
||||
|
||||
private void setUp() {
|
||||
final Context context = getInstrumentation().getTargetContext();
|
||||
|
||||
removeServices();
|
||||
|
||||
LocalServices.addService(DisplayManagerInternal.class,
|
||||
mock(DisplayManagerInternal.class));
|
||||
|
||||
LocalServices.addService(PowerManagerInternal.class,
|
||||
mock(PowerManagerInternal.class));
|
||||
final PowerManagerInternal pm =
|
||||
LocalServices.getService(PowerManagerInternal.class);
|
||||
doNothing().when(pm).registerLowPowerModeObserver(any());
|
||||
PowerSaveState state = new PowerSaveState.Builder().build();
|
||||
doReturn(state).when(pm).getLowPowerState(anyInt());
|
||||
|
||||
LocalServices.addService(ActivityManagerInternal.class,
|
||||
mock(ActivityManagerInternal.class));
|
||||
LocalServices.addService(ActivityTaskManagerInternal.class,
|
||||
mock(ActivityTaskManagerInternal.class));
|
||||
final ActivityTaskManagerInternal atm =
|
||||
LocalServices.getService(ActivityTaskManagerInternal.class);
|
||||
doAnswer((InvocationOnMock invocationOnMock) -> {
|
||||
final Runnable runnable = invocationOnMock.<Runnable>getArgument(0);
|
||||
if (runnable != null) {
|
||||
runnable.run();
|
||||
}
|
||||
return null;
|
||||
}).when(atm).notifyKeyguardFlagsChanged(any(), anyInt());
|
||||
|
||||
InputManagerService ims = mock(InputManagerService.class);
|
||||
// InputChannel is final and can't be mocked.
|
||||
InputChannel[] input = InputChannel.openInputChannelPair(TAG_WM);
|
||||
if (input != null && input.length > 1) {
|
||||
doReturn(input[1]).when(ims).monitorInput(anyString(), anyInt());
|
||||
}
|
||||
ActivityTaskManagerService atms = mock(ActivityTaskManagerService.class);
|
||||
when(atms.getGlobalLock()).thenReturn(new WindowManagerGlobalLock());
|
||||
|
||||
mService = WindowManagerService.main(context, ims, false, false,
|
||||
mPolicy = new TestWindowManagerPolicy(
|
||||
WindowManagerServiceRule.this::getWindowManagerService), atms);
|
||||
mService.mTransactionFactory = () -> {
|
||||
final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
|
||||
mSurfaceTransactions.add(new WeakReference<>(transaction));
|
||||
return transaction;
|
||||
};
|
||||
mService.mSurfaceBuilderFactory = session -> new SurfaceControl.Builder(session) {
|
||||
@Override
|
||||
public SurfaceControl build() {
|
||||
final SurfaceControl control = super.build();
|
||||
mSurfaceControls.add(new WeakReference<>(control));
|
||||
return control;
|
||||
}
|
||||
};
|
||||
|
||||
mService.onInitReady();
|
||||
|
||||
final Display display = mService.mDisplayManager.getDisplay(DEFAULT_DISPLAY);
|
||||
// Display creation is driven by the ActivityManagerService via
|
||||
// ActivityStackSupervisor. We emulate those steps here.
|
||||
mService.mRoot.createDisplayContent(display, mock(ActivityDisplay.class));
|
||||
}
|
||||
|
||||
private void removeServices() {
|
||||
LocalServices.removeServiceForTest(DisplayManagerInternal.class);
|
||||
LocalServices.removeServiceForTest(PowerManagerInternal.class);
|
||||
LocalServices.removeServiceForTest(ActivityManagerInternal.class);
|
||||
LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
|
||||
LocalServices.removeServiceForTest(WindowManagerInternal.class);
|
||||
LocalServices.removeServiceForTest(WindowManagerPolicy.class);
|
||||
}
|
||||
|
||||
private void tearDown() {
|
||||
cancelAllPendingAnimations();
|
||||
waitUntilWindowManagerHandlersIdle();
|
||||
destroyAllSurfaceTransactions();
|
||||
destroyAllSurfaceControls();
|
||||
removeServices();
|
||||
mService = null;
|
||||
mPolicy = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
WindowManagerService getWindowManagerService() {
|
||||
return mService;
|
||||
}
|
||||
|
||||
private void cancelAllPendingAnimations() {
|
||||
for (final WeakReference<SurfaceControl> reference : mSurfaceControls) {
|
||||
final SurfaceControl sc = reference.get();
|
||||
if (sc != null) {
|
||||
mService.mSurfaceAnimationRunner.onAnimationCancelled(sc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void waitUntilWindowManagerHandlersIdle() {
|
||||
final WindowManagerService wm = getWindowManagerService();
|
||||
if (wm == null) {
|
||||
return;
|
||||
}
|
||||
// Removing delayed FORCE_GC message decreases time for waiting idle.
|
||||
wm.mH.removeMessages(WindowManagerService.H.FORCE_GC);
|
||||
waitHandlerIdle(wm.mH);
|
||||
waitHandlerIdle(wm.mAnimationHandler);
|
||||
waitHandlerIdle(SurfaceAnimationThread.getHandler());
|
||||
}
|
||||
|
||||
private static void waitHandlerIdle(Handler handler) {
|
||||
if (handler.hasMessagesOrCallbacks()) {
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
// Wait for delayed messages are processed.
|
||||
handler.getLooper().getQueue().addIdleHandler(() -> {
|
||||
if (handler.hasMessagesOrCallbacks()) {
|
||||
return true; // keep idle handler.
|
||||
}
|
||||
latch.countDown();
|
||||
return false; // remove idle handler.
|
||||
});
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void destroyAllSurfaceTransactions() {
|
||||
for (final WeakReference<Transaction> reference : mSurfaceTransactions) {
|
||||
final Transaction transaction = reference.get();
|
||||
if (transaction != null) {
|
||||
reference.clear();
|
||||
transaction.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void destroyAllSurfaceControls() {
|
||||
for (final WeakReference<SurfaceControl> reference : mSurfaceControls) {
|
||||
final SurfaceControl control = reference.get();
|
||||
if (control != null) {
|
||||
reference.clear();
|
||||
control.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 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;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Build/InstallRun:
|
||||
* atest FrameworksServicesTests:WindowManagerServiceRuleTest
|
||||
*/
|
||||
@Presubmit
|
||||
@SmallTest
|
||||
public class WindowManagerServiceRuleTest {
|
||||
|
||||
@Rule
|
||||
public final WindowManagerServiceRule mRule = new WindowManagerServiceRule();
|
||||
|
||||
@Test
|
||||
public void testWindowManagerSetUp() {
|
||||
assertThat(mRule.getWindowManagerService(), notNullValue());
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,7 @@ import android.view.WindowManager;
|
||||
import com.android.server.AttributeCache;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
@@ -95,17 +96,22 @@ class WindowTestsBase {
|
||||
public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
|
||||
new DexmakerShareClassLoaderRule();
|
||||
|
||||
@Rule
|
||||
public final WindowManagerServiceRule mWmRule = new WindowManagerServiceRule();
|
||||
|
||||
static WindowState.PowerManagerWrapper sPowerManagerWrapper; // TODO(roosa): make non-static.
|
||||
static WindowState.PowerManagerWrapper sPowerManagerWrapper;
|
||||
|
||||
@BeforeClass
|
||||
public static void setUpOnceBase() {
|
||||
AttributeCache.init(getInstrumentation().getTargetContext());
|
||||
|
||||
WmServiceUtils.setUpWindowManagerService();
|
||||
|
||||
sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void tearDonwOnceBase() {
|
||||
WmServiceUtils.tearDownWindowManagerService();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUpBase() {
|
||||
// If @Before throws an exception, the error isn't logged. This will make sure any failures
|
||||
@@ -115,7 +121,7 @@ class WindowTestsBase {
|
||||
|
||||
final Context context = getInstrumentation().getTargetContext();
|
||||
|
||||
mWm = mWmRule.getWindowManagerService();
|
||||
mWm = WmServiceUtils.getWindowManagerService();
|
||||
beforeCreateDisplay();
|
||||
|
||||
context.getDisplay().getDisplayInfo(mDisplayInfo);
|
||||
@@ -214,7 +220,7 @@ class WindowTestsBase {
|
||||
* Waits until the main handler for WM has processed all messages.
|
||||
*/
|
||||
void waitUntilHandlersIdle() {
|
||||
mWmRule.waitUntilWindowManagerHandlersIdle();
|
||||
WmServiceUtils.waitUntilWindowManagerHandlersIdle();
|
||||
}
|
||||
|
||||
private WindowToken createWindowToken(
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import static android.testing.DexmakerShareClassLoaderRule.runWithDexmakerShareClassLoader;
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
|
||||
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyString;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.nullable;
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
||||
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
|
||||
|
||||
import android.app.ActivityManagerInternal;
|
||||
import android.app.AppOpsManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.IntentFilter;
|
||||
import android.database.ContentObserver;
|
||||
import android.hardware.display.DisplayManagerInternal;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.os.PowerManagerInternal;
|
||||
import android.os.PowerSaveState;
|
||||
import android.os.UserHandle;
|
||||
import android.view.Display;
|
||||
import android.view.InputChannel;
|
||||
|
||||
import com.android.dx.mockito.inline.extended.StaticMockitoSession;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.LockGuard;
|
||||
import com.android.server.Watchdog;
|
||||
import com.android.server.input.InputManagerService;
|
||||
import com.android.server.policy.WindowManagerPolicy;
|
||||
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.quality.Strictness;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
/**
|
||||
* A Test utility class to create a mock {@link WindowManagerService} instance for tests.
|
||||
*/
|
||||
class WmServiceUtils {
|
||||
private static StaticMockitoSession sMockitoSession;
|
||||
private static WindowManagerService sService;
|
||||
private static TestWindowManagerPolicy sPolicy;
|
||||
|
||||
static void setUpWindowManagerService() {
|
||||
sMockitoSession = mockitoSession()
|
||||
.spyStatic(LockGuard.class)
|
||||
.spyStatic(Watchdog.class)
|
||||
.strictness(Strictness.LENIENT)
|
||||
.startMocking();
|
||||
|
||||
runWithDexmakerShareClassLoader(WmServiceUtils::setUpTestWindowService);
|
||||
}
|
||||
|
||||
static void tearDownWindowManagerService() {
|
||||
waitUntilWindowManagerHandlersIdle();
|
||||
removeLocalServices();
|
||||
sService = null;
|
||||
sPolicy = null;
|
||||
|
||||
sMockitoSession.finishMocking();
|
||||
}
|
||||
|
||||
private static void setUpTestWindowService() {
|
||||
doReturn(null).when(() -> LockGuard.installLock(any(), anyInt()));
|
||||
doReturn(mock(Watchdog.class)).when(Watchdog::getInstance);
|
||||
|
||||
final Context context = getInstrumentation().getTargetContext();
|
||||
spyOn(context);
|
||||
|
||||
doReturn(null).when(context)
|
||||
.registerReceiver(nullable(BroadcastReceiver.class), any(IntentFilter.class));
|
||||
doReturn(null).when(context)
|
||||
.registerReceiverAsUser(any(BroadcastReceiver.class), any(UserHandle.class),
|
||||
any(IntentFilter.class), nullable(String.class), nullable(Handler.class));
|
||||
|
||||
final ContentResolver contentResolver = context.getContentResolver();
|
||||
spyOn(contentResolver);
|
||||
doNothing().when(contentResolver)
|
||||
.registerContentObserver(any(Uri.class), anyBoolean(), any(ContentObserver.class),
|
||||
anyInt());
|
||||
|
||||
final AppOpsManager appOpsManager = mock(AppOpsManager.class);
|
||||
doReturn(appOpsManager).when(context)
|
||||
.getSystemService(eq(Context.APP_OPS_SERVICE));
|
||||
|
||||
removeLocalServices();
|
||||
|
||||
final DisplayManagerInternal dmi = mock(DisplayManagerInternal.class);
|
||||
LocalServices.addService(DisplayManagerInternal.class, dmi);
|
||||
|
||||
final PowerManagerInternal pmi = mock(PowerManagerInternal.class);
|
||||
LocalServices.addService(PowerManagerInternal.class, pmi);
|
||||
final PowerSaveState state = new PowerSaveState.Builder().build();
|
||||
doReturn(state).when(pmi).getLowPowerState(anyInt());
|
||||
|
||||
final ActivityManagerInternal ami = mock(ActivityManagerInternal.class);
|
||||
LocalServices.addService(ActivityManagerInternal.class, ami);
|
||||
|
||||
final ActivityTaskManagerInternal atmi = mock(ActivityTaskManagerInternal.class);
|
||||
LocalServices.addService(ActivityTaskManagerInternal.class, atmi);
|
||||
doAnswer((InvocationOnMock invocationOnMock) -> {
|
||||
final Runnable runnable = invocationOnMock.getArgument(0);
|
||||
if (runnable != null) {
|
||||
runnable.run();
|
||||
}
|
||||
return null;
|
||||
}).when(atmi).notifyKeyguardFlagsChanged(nullable(Runnable.class), anyInt());
|
||||
|
||||
final InputManagerService ims = mock(InputManagerService.class);
|
||||
// InputChannel is final and can't be mocked.
|
||||
final InputChannel[] input = InputChannel.openInputChannelPair(TAG_WM);
|
||||
if (input != null && input.length > 1) {
|
||||
doReturn(input[1]).when(ims).monitorInput(anyString(), anyInt());
|
||||
}
|
||||
|
||||
final ActivityTaskManagerService atms = mock(ActivityTaskManagerService.class);
|
||||
final WindowManagerGlobalLock wmLock = new WindowManagerGlobalLock();
|
||||
doReturn(wmLock).when(atms).getGlobalLock();
|
||||
|
||||
sPolicy = new TestWindowManagerPolicy(WmServiceUtils::getWindowManagerService);
|
||||
sService = WindowManagerService.main(context, ims, false, false, sPolicy, atms);
|
||||
|
||||
sService.onInitReady();
|
||||
|
||||
final Display display = sService.mDisplayManager.getDisplay(DEFAULT_DISPLAY);
|
||||
// Display creation is driven by the ActivityManagerService via
|
||||
// ActivityStackSupervisor. We emulate those steps here.
|
||||
sService.mRoot.createDisplayContent(display, mock(ActivityDisplay.class));
|
||||
}
|
||||
|
||||
private static void removeLocalServices() {
|
||||
LocalServices.removeServiceForTest(DisplayManagerInternal.class);
|
||||
LocalServices.removeServiceForTest(PowerManagerInternal.class);
|
||||
LocalServices.removeServiceForTest(ActivityManagerInternal.class);
|
||||
LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
|
||||
LocalServices.removeServiceForTest(WindowManagerInternal.class);
|
||||
LocalServices.removeServiceForTest(WindowManagerPolicy.class);
|
||||
}
|
||||
|
||||
static WindowManagerService getWindowManagerService() {
|
||||
return sService;
|
||||
}
|
||||
|
||||
static void waitUntilWindowManagerHandlersIdle() {
|
||||
final WindowManagerService wm = getWindowManagerService();
|
||||
if (wm == null) {
|
||||
return;
|
||||
}
|
||||
// Removing delayed FORCE_GC message decreases time for waiting idle.
|
||||
wm.mH.removeMessages(WindowManagerService.H.FORCE_GC);
|
||||
waitHandlerIdle(wm.mH);
|
||||
waitHandlerIdle(wm.mAnimationHandler);
|
||||
waitHandlerIdle(SurfaceAnimationThread.getHandler());
|
||||
}
|
||||
|
||||
private static void waitHandlerIdle(Handler handler) {
|
||||
if (!handler.hasMessagesOrCallbacks()) {
|
||||
return;
|
||||
}
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
// Wait for delayed messages are processed.
|
||||
handler.getLooper().getQueue().addIdleHandler(() -> {
|
||||
if (handler.hasMessagesOrCallbacks()) {
|
||||
return true; // keep idle handler.
|
||||
}
|
||||
latch.countDown();
|
||||
return false; // remove idle handler.
|
||||
});
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user