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