1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.wm; 18 19 import static android.app.AppOpsManager.OP_NONE; 20 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 22 import static android.os.Process.SYSTEM_UID; 23 import static android.view.Display.DEFAULT_DISPLAY; 24 import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; 25 import static android.view.View.VISIBLE; 26 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; 27 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; 28 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW; 29 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG; 30 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY; 31 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 32 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER; 33 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; 34 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG; 35 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; 36 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; 37 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; 38 39 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 40 41 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; 42 43 import static org.mockito.Mockito.mock; 44 45 46 import android.content.Context; 47 import android.content.res.Configuration; 48 import android.hardware.display.DisplayManagerGlobal; 49 import android.testing.DexmakerShareClassLoaderRule; 50 import android.util.Log; 51 import android.view.Display; 52 import android.view.DisplayInfo; 53 import android.view.IWindow; 54 import android.view.Surface; 55 import android.view.SurfaceControl.Transaction; 56 import android.view.WindowManager; 57 58 import com.android.server.AttributeCache; 59 import com.android.server.wm.utils.MockTracker; 60 61 import org.junit.After; 62 import org.junit.AfterClass; 63 import org.junit.Before; 64 import org.junit.BeforeClass; 65 import org.junit.Rule; 66 67 import java.io.IOException; 68 import java.util.HashSet; 69 import java.util.LinkedList; 70 71 /** 72 * Common base class for window manager unit test classes. 73 * 74 * Make sure any requests to WM hold the WM lock if needed b/73966377 75 */ 76 class WindowTestsBase { 77 private static final String TAG = WindowTestsBase.class.getSimpleName(); 78 79 WindowManagerService mWm; 80 private final IWindow mIWindow = new TestIWindow(); 81 private Session mMockSession; 82 // The default display is removed in {@link #setUp} and then we iterate over all displays to 83 // make sure we don't collide with any existing display. If we run into no other display, the 84 // added display should be treated as default. This cannot be the default display 85 private static int sNextDisplayId = DEFAULT_DISPLAY + 1; 86 static int sNextStackId = 1000; 87 88 /** Non-default display. */ 89 DisplayContent mDisplayContent; 90 DisplayInfo mDisplayInfo = new DisplayInfo(); 91 WindowState mWallpaperWindow; 92 WindowState mImeWindow; 93 WindowState mImeDialogWindow; 94 WindowState mStatusBarWindow; 95 WindowState mDockedDividerWindow; 96 WindowState mNavBarWindow; 97 WindowState mAppWindow; 98 WindowState mChildAppWindowAbove; 99 WindowState mChildAppWindowBelow; 100 HashSet<WindowState> mCommonWindows; 101 102 private MockTracker mMockTracker; 103 104 /** 105 * Spied {@link Transaction} class than can be used to verify calls. 106 */ 107 Transaction mTransaction; 108 109 @Rule 110 public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule = 111 new DexmakerShareClassLoaderRule(); 112 @Rule 113 public final SystemServicesTestRule mSystemServicesTestRule = new SystemServicesTestRule(); 114 115 static WindowState.PowerManagerWrapper sPowerManagerWrapper; 116 117 @BeforeClass setUpOnceBase()118 public static void setUpOnceBase() { 119 AttributeCache.init(getInstrumentation().getTargetContext()); 120 121 sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class); 122 } 123 124 @AfterClass tearDownOnceBase()125 public static void tearDownOnceBase() throws IOException { 126 sPowerManagerWrapper = null; 127 } 128 129 @Before setUpBase()130 public void setUpBase() { 131 mMockTracker = new MockTracker(); 132 133 // If @Before throws an exception, the error isn't logged. This will make sure any failures 134 // in the set up are clear. This can be removed when b/37850063 is fixed. 135 try { 136 mMockSession = mock(Session.class); 137 mTransaction = spy(StubTransaction.class); 138 139 final Context context = getInstrumentation().getTargetContext(); 140 141 mWm = mSystemServicesTestRule.getWindowManagerService(); 142 143 // Setup factory classes to prevent calls to native code. 144 145 // Return a spied Transaction class than can be used to verify calls. 146 mWm.mTransactionFactory = () -> mTransaction; 147 // Return a SurfaceControl.Builder class that creates mocked SurfaceControl instances. 148 mWm.mSurfaceBuilderFactory = (unused) -> new MockSurfaceControlBuilder(); 149 // Return mocked Surface instances. 150 mWm.mSurfaceFactory = () -> mock(Surface.class); 151 152 beforeCreateDisplay(); 153 154 context.getDisplay().getDisplayInfo(mDisplayInfo); 155 mDisplayContent = createNewDisplay(); 156 mWm.mDisplayEnabled = true; 157 mWm.mDisplayReady = true; 158 159 // Set-up some common windows. 160 mCommonWindows = new HashSet<>(); 161 synchronized (mWm.mGlobalLock) { 162 mWallpaperWindow = createCommonWindow(null, TYPE_WALLPAPER, "wallpaperWindow"); 163 mImeWindow = createCommonWindow(null, TYPE_INPUT_METHOD, "mImeWindow"); 164 mDisplayContent.mInputMethodWindow = mImeWindow; 165 mImeDialogWindow = createCommonWindow(null, TYPE_INPUT_METHOD_DIALOG, 166 "mImeDialogWindow"); 167 mStatusBarWindow = createCommonWindow(null, TYPE_STATUS_BAR, "mStatusBarWindow"); 168 mNavBarWindow = createCommonWindow(null, TYPE_NAVIGATION_BAR, "mNavBarWindow"); 169 mDockedDividerWindow = createCommonWindow(null, TYPE_DOCK_DIVIDER, 170 "mDockedDividerWindow"); 171 mAppWindow = createCommonWindow(null, TYPE_BASE_APPLICATION, "mAppWindow"); 172 mChildAppWindowAbove = createCommonWindow(mAppWindow, 173 TYPE_APPLICATION_ATTACHED_DIALOG, 174 "mChildAppWindowAbove"); 175 mChildAppWindowBelow = createCommonWindow(mAppWindow, 176 TYPE_APPLICATION_MEDIA_OVERLAY, 177 "mChildAppWindowBelow"); 178 } 179 // Adding a display will cause freezing the display. Make sure to wait until it's 180 // unfrozen to not run into race conditions with the tests. 181 waitUntilHandlersIdle(); 182 } catch (Exception e) { 183 Log.e(TAG, "Failed to set up test", e); 184 throw e; 185 } 186 } 187 beforeCreateDisplay()188 void beforeCreateDisplay() { 189 // Called before display is created. 190 } 191 192 @After tearDownBase()193 public void tearDownBase() { 194 // If @After throws an exception, the error isn't logged. This will make sure any failures 195 // in the tear down are clear. This can be removed when b/37850063 is fixed. 196 try { 197 // Test may schedule to perform surface placement or other messages. Wait until a 198 // stable state to clean up for consistency. 199 waitUntilHandlersIdle(); 200 201 final LinkedList<WindowState> nonCommonWindows = new LinkedList<>(); 202 203 synchronized (mWm.mGlobalLock) { 204 mWm.mRoot.forAllWindows(w -> { 205 if (!mCommonWindows.contains(w)) { 206 nonCommonWindows.addLast(w); 207 } 208 }, true /* traverseTopToBottom */); 209 210 while (!nonCommonWindows.isEmpty()) { 211 nonCommonWindows.pollLast().removeImmediately(); 212 } 213 214 for (int i = mWm.mRoot.mChildren.size() - 1; i >= 0; --i) { 215 final DisplayContent displayContent = mWm.mRoot.mChildren.get(i); 216 if (!displayContent.isDefaultDisplay) { 217 displayContent.removeImmediately(); 218 } 219 } 220 // Remove app transition & window freeze timeout callbacks to prevent unnecessary 221 // actions after test. 222 mWm.getDefaultDisplayContentLocked().mAppTransition 223 .removeAppTransitionTimeoutCallbacks(); 224 mWm.mH.removeMessages(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT); 225 mDisplayContent.mInputMethodTarget = null; 226 } 227 228 // Cleaned up everything in Handler. 229 mSystemServicesTestRule.cleanupWindowManagerHandlers(); 230 } catch (Exception e) { 231 Log.e(TAG, "Failed to tear down test", e); 232 throw e; 233 } finally { 234 mMockTracker.close(); 235 mMockTracker = null; 236 } 237 238 } 239 createCommonWindow(WindowState parent, int type, String name)240 private WindowState createCommonWindow(WindowState parent, int type, String name) { 241 synchronized (mWm.mGlobalLock) { 242 final WindowState win = createWindow(parent, type, name); 243 mCommonWindows.add(win); 244 // Prevent common windows from been IMe targets 245 win.mAttrs.flags |= FLAG_NOT_FOCUSABLE; 246 return win; 247 } 248 } 249 250 /** 251 * Waits until the main handler for WM has processed all messages. 252 */ waitUntilHandlersIdle()253 void waitUntilHandlersIdle() { 254 mSystemServicesTestRule.waitUntilWindowManagerHandlersIdle(); 255 } 256 createWindowToken( DisplayContent dc, int windowingMode, int activityType, int type)257 private WindowToken createWindowToken( 258 DisplayContent dc, int windowingMode, int activityType, int type) { 259 synchronized (mWm.mGlobalLock) { 260 if (type < FIRST_APPLICATION_WINDOW || type > LAST_APPLICATION_WINDOW) { 261 return WindowTestUtils.createTestWindowToken(type, dc); 262 } 263 264 return createAppWindowToken(dc, windowingMode, activityType); 265 } 266 } 267 createAppWindowToken(DisplayContent dc, int windowingMode, int activityType)268 AppWindowToken createAppWindowToken(DisplayContent dc, int windowingMode, int activityType) { 269 return createTestAppWindowToken(dc, windowingMode, activityType); 270 } 271 createTestAppWindowToken(DisplayContent dc, int windowingMode, int activityType)272 WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int 273 windowingMode, int activityType) { 274 final TaskStack stack = createTaskStackOnDisplay(windowingMode, activityType, dc); 275 final Task task = createTaskInStack(stack, 0 /* userId */); 276 final WindowTestUtils.TestAppWindowToken appWindowToken = 277 WindowTestUtils.createTestAppWindowToken(dc); 278 task.addChild(appWindowToken, 0); 279 return appWindowToken; 280 } 281 createWindow(WindowState parent, int type, String name)282 WindowState createWindow(WindowState parent, int type, String name) { 283 synchronized (mWm.mGlobalLock) { 284 return (parent == null) 285 ? createWindow(parent, type, mDisplayContent, name) 286 : createWindow(parent, type, parent.mToken, name); 287 } 288 } 289 createWindow(WindowState parent, int type, String name, int ownerId)290 WindowState createWindow(WindowState parent, int type, String name, int ownerId) { 291 synchronized (mWm.mGlobalLock) { 292 return (parent == null) 293 ? createWindow(parent, type, mDisplayContent, name, ownerId) 294 : createWindow(parent, type, parent.mToken, name, ownerId); 295 } 296 } 297 createWindowOnStack(WindowState parent, int windowingMode, int activityType, int type, DisplayContent dc, String name)298 WindowState createWindowOnStack(WindowState parent, int windowingMode, int activityType, 299 int type, DisplayContent dc, String name) { 300 synchronized (mWm.mGlobalLock) { 301 final WindowToken token = createWindowToken(dc, windowingMode, activityType, type); 302 return createWindow(parent, type, token, name); 303 } 304 } 305 createAppWindow(Task task, int type, String name)306 WindowState createAppWindow(Task task, int type, String name) { 307 synchronized (mWm.mGlobalLock) { 308 final AppWindowToken token = WindowTestUtils.createTestAppWindowToken(mDisplayContent); 309 task.addChild(token, 0); 310 return createWindow(null, type, token, name); 311 } 312 } 313 createWindow(WindowState parent, int type, DisplayContent dc, String name)314 WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name) { 315 synchronized (mWm.mGlobalLock) { 316 final WindowToken token = createWindowToken( 317 dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type); 318 return createWindow(parent, type, token, name, 0 /* ownerId */); 319 } 320 } 321 createWindow(WindowState parent, int type, DisplayContent dc, String name, int ownerId)322 WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name, 323 int ownerId) { 324 synchronized (mWm.mGlobalLock) { 325 final WindowToken token = createWindowToken( 326 dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type); 327 return createWindow(parent, type, token, name, ownerId); 328 } 329 } 330 createWindow(WindowState parent, int type, DisplayContent dc, String name, boolean ownerCanAddInternalSystemWindow)331 WindowState createWindow(WindowState parent, int type, DisplayContent dc, String name, 332 boolean ownerCanAddInternalSystemWindow) { 333 synchronized (mWm.mGlobalLock) { 334 final WindowToken token = createWindowToken( 335 dc, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, type); 336 return createWindow(parent, type, token, name, 0 /* ownerId */, 337 ownerCanAddInternalSystemWindow); 338 } 339 } 340 createWindow(WindowState parent, int type, WindowToken token, String name)341 WindowState createWindow(WindowState parent, int type, WindowToken token, String name) { 342 synchronized (mWm.mGlobalLock) { 343 return createWindow(parent, type, token, name, 0 /* ownerId */, 344 false /* ownerCanAddInternalSystemWindow */); 345 } 346 } 347 createWindow(WindowState parent, int type, WindowToken token, String name, int ownerId)348 WindowState createWindow(WindowState parent, int type, WindowToken token, String name, 349 int ownerId) { 350 synchronized (mWm.mGlobalLock) { 351 return createWindow(parent, type, token, name, ownerId, 352 false /* ownerCanAddInternalSystemWindow */); 353 } 354 } 355 createWindow(WindowState parent, int type, WindowToken token, String name, int ownerId, boolean ownerCanAddInternalSystemWindow)356 WindowState createWindow(WindowState parent, int type, WindowToken token, String name, 357 int ownerId, boolean ownerCanAddInternalSystemWindow) { 358 return createWindow(parent, type, token, name, ownerId, ownerCanAddInternalSystemWindow, 359 mWm, mMockSession, mIWindow); 360 } 361 createWindow(WindowState parent, int type, WindowToken token, String name, int ownerId, boolean ownerCanAddInternalSystemWindow, WindowManagerService service, Session session, IWindow iWindow)362 static WindowState createWindow(WindowState parent, int type, WindowToken token, 363 String name, int ownerId, boolean ownerCanAddInternalSystemWindow, 364 WindowManagerService service, Session session, IWindow iWindow) { 365 synchronized (service.mGlobalLock) { 366 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(type); 367 attrs.setTitle(name); 368 369 final WindowState w = new WindowState(service, session, iWindow, token, parent, 370 OP_NONE, 371 0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow, 372 sPowerManagerWrapper); 373 // TODO: Probably better to make this call in the WindowState ctor to avoid errors with 374 // adding it to the token... 375 token.addWindow(w); 376 return w; 377 } 378 } 379 380 /** Creates a {@link TaskStack} and adds it to the specified {@link DisplayContent}. */ createTaskStackOnDisplay(DisplayContent dc)381 TaskStack createTaskStackOnDisplay(DisplayContent dc) { 382 synchronized (mWm.mGlobalLock) { 383 return createTaskStackOnDisplay(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, dc); 384 } 385 } 386 createTaskStackOnDisplay(int windowingMode, int activityType, DisplayContent dc)387 TaskStack createTaskStackOnDisplay(int windowingMode, int activityType, DisplayContent dc) { 388 synchronized (mWm.mGlobalLock) { 389 final Configuration overrideConfig = new Configuration(); 390 overrideConfig.windowConfiguration.setWindowingMode(windowingMode); 391 overrideConfig.windowConfiguration.setActivityType(activityType); 392 final int stackId = ++sNextStackId; 393 final TaskStack stack = new TaskStack(mWm, stackId, mock(ActivityStack.class)); 394 dc.setStackOnDisplay(stackId, true, stack); 395 stack.onRequestedOverrideConfigurationChanged(overrideConfig); 396 return stack; 397 } 398 } 399 400 /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */ createTaskInStack(TaskStack stack, int userId)401 Task createTaskInStack(TaskStack stack, int userId) { 402 return WindowTestUtils.createTaskInStack(mWm, stack, userId); 403 } 404 405 /** Creates a {@link DisplayContent} and adds it to the system. */ createNewDisplay()406 DisplayContent createNewDisplay() { 407 return createNewDisplay(mDisplayInfo); 408 } 409 410 /** Creates a {@link DisplayContent} and adds it to the system. */ createNewDisplay(DisplayInfo displayInfo)411 DisplayContent createNewDisplay(DisplayInfo displayInfo) { 412 final int displayId = sNextDisplayId++; 413 final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId, 414 displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS); 415 synchronized (mWm.mGlobalLock) { 416 return new DisplayContent(display, mWm, mock(ActivityDisplay.class)); 417 } 418 } 419 420 /** 421 * Creates a {@link DisplayContent} with given display state and adds it to the system. 422 * 423 * @param displayState For initializing the state of the display. See 424 * {@link Display#getState()}. 425 */ createNewDisplay(int displayState)426 DisplayContent createNewDisplay(int displayState) { 427 // Leverage main display info & initialize it with display state for given displayId. 428 DisplayInfo displayInfo = new DisplayInfo(); 429 displayInfo.copyFrom(mDisplayInfo); 430 displayInfo.state = displayState; 431 final int displayId = sNextDisplayId++; 432 final Display display = new Display(DisplayManagerGlobal.getInstance(), displayId, 433 displayInfo, DEFAULT_DISPLAY_ADJUSTMENTS); 434 synchronized (mWm.mGlobalLock) { 435 // Display creation is driven by DisplayWindowController via ActivityStackSupervisor. 436 // We skip those steps here. 437 final ActivityDisplay mockAd = mock(ActivityDisplay.class); 438 return mWm.mRoot.createDisplayContent(display, mockAd); 439 } 440 } 441 442 /** Creates a {@link com.android.server.wm.WindowTestUtils.TestWindowState} */ createWindowState(WindowManager.LayoutParams attrs, WindowToken token)443 WindowTestUtils.TestWindowState createWindowState(WindowManager.LayoutParams attrs, 444 WindowToken token) { 445 synchronized (mWm.mGlobalLock) { 446 return new WindowTestUtils.TestWindowState(mWm, mMockSession, mIWindow, attrs, token); 447 } 448 } 449 450 /** Creates a {@link DisplayContent} as parts of simulate display info for test. */ createMockSimulatedDisplay()451 DisplayContent createMockSimulatedDisplay() { 452 DisplayInfo displayInfo = new DisplayInfo(); 453 displayInfo.copyFrom(mDisplayInfo); 454 displayInfo.type = Display.TYPE_VIRTUAL; 455 displayInfo.ownerUid = SYSTEM_UID; 456 return createNewDisplay(displayInfo); 457 } 458 } 459