1 /* 2 * Copyright (C) 2017 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 com.android.server.wm.WindowManagerDebugConfig.DEBUG; 20 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; 21 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 22 import static com.android.server.wm.WindowManagerService.H.REPORT_WINDOWS_CHANGE; 23 import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD; 24 25 import android.os.Debug; 26 import android.os.Trace; 27 import android.util.Slog; 28 import android.util.SparseIntArray; 29 30 import java.io.PrintWriter; 31 32 /** 33 * Positions windows and their surfaces. 34 * 35 * It sets positions of windows by calculating their frames and then applies this by positioning 36 * surfaces according to these frames. Z layer is still assigned withing WindowManagerService. 37 */ 38 class WindowSurfacePlacer { 39 private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowSurfacePlacer" : TAG_WM; 40 private final WindowManagerService mService; 41 42 private boolean mInLayout = false; 43 44 /** Only do a maximum of 6 repeated layouts. After that quit */ 45 private int mLayoutRepeatCount; 46 47 static final int SET_UPDATE_ROTATION = 1 << 0; 48 static final int SET_ORIENTATION_CHANGE_COMPLETE = 1 << 2; 49 static final int SET_WALLPAPER_ACTION_PENDING = 1 << 3; 50 51 private boolean mTraversalScheduled; 52 private int mDeferDepth = 0; 53 54 private final SparseIntArray mTempTransitionReasons = new SparseIntArray(); 55 56 private final Runnable mPerformSurfacePlacement; 57 WindowSurfacePlacer(WindowManagerService service)58 public WindowSurfacePlacer(WindowManagerService service) { 59 mService = service; 60 mPerformSurfacePlacement = () -> { 61 synchronized (mService.mGlobalLock) { 62 performSurfacePlacement(); 63 } 64 }; 65 } 66 67 /** 68 * See {@link WindowManagerService#deferSurfaceLayout()} 69 */ deferLayout()70 void deferLayout() { 71 mDeferDepth++; 72 } 73 74 /** 75 * See {@link WindowManagerService#continueSurfaceLayout()} 76 */ continueLayout()77 void continueLayout() { 78 mDeferDepth--; 79 if (mDeferDepth <= 0) { 80 performSurfacePlacement(); 81 } 82 } 83 isLayoutDeferred()84 boolean isLayoutDeferred() { 85 return mDeferDepth > 0; 86 } 87 performSurfacePlacementIfScheduled()88 void performSurfacePlacementIfScheduled() { 89 if (mTraversalScheduled) { 90 performSurfacePlacement(); 91 } 92 } 93 performSurfacePlacement()94 final void performSurfacePlacement() { 95 performSurfacePlacement(false /* force */); 96 } 97 performSurfacePlacement(boolean force)98 final void performSurfacePlacement(boolean force) { 99 if (mDeferDepth > 0 && !force) { 100 return; 101 } 102 int loopCount = 6; 103 do { 104 mTraversalScheduled = false; 105 performSurfacePlacementLoop(); 106 mService.mAnimationHandler.removeCallbacks(mPerformSurfacePlacement); 107 loopCount--; 108 } while (mTraversalScheduled && loopCount > 0); 109 mService.mRoot.mWallpaperActionPending = false; 110 } 111 performSurfacePlacementLoop()112 private void performSurfacePlacementLoop() { 113 if (mInLayout) { 114 if (DEBUG) { 115 throw new RuntimeException("Recursive call!"); 116 } 117 Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout. Callers=" 118 + Debug.getCallers(3)); 119 return; 120 } 121 122 // TODO(multi-display): 123 final DisplayContent defaultDisplay = mService.getDefaultDisplayContentLocked(); 124 if (defaultDisplay.mWaitingForConfig) { 125 // Our configuration has changed (most likely rotation), but we 126 // don't yet have the complete configuration to report to 127 // applications. Don't do any window layout until we have it. 128 return; 129 } 130 131 if (!mService.mDisplayReady) { 132 // Not yet initialized, nothing to do. 133 return; 134 } 135 136 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout"); 137 mInLayout = true; 138 139 boolean recoveringMemory = false; 140 if (!mService.mForceRemoves.isEmpty()) { 141 recoveringMemory = true; 142 // Wait a little bit for things to settle down, and off we go. 143 while (!mService.mForceRemoves.isEmpty()) { 144 final WindowState ws = mService.mForceRemoves.remove(0); 145 Slog.i(TAG, "Force removing: " + ws); 146 ws.removeImmediately(); 147 } 148 Slog.w(TAG, "Due to memory failure, waiting a bit for next layout"); 149 Object tmp = new Object(); 150 synchronized (tmp) { 151 try { 152 tmp.wait(250); 153 } catch (InterruptedException e) { 154 } 155 } 156 } 157 158 try { 159 mService.mRoot.performSurfacePlacement(recoveringMemory); 160 161 mInLayout = false; 162 163 if (mService.mRoot.isLayoutNeeded()) { 164 if (++mLayoutRepeatCount < 6) { 165 requestTraversal(); 166 } else { 167 Slog.e(TAG, "Performed 6 layouts in a row. Skipping"); 168 mLayoutRepeatCount = 0; 169 } 170 } else { 171 mLayoutRepeatCount = 0; 172 } 173 174 if (mService.mWindowsChanged && !mService.mWindowChangeListeners.isEmpty()) { 175 mService.mH.removeMessages(REPORT_WINDOWS_CHANGE); 176 mService.mH.sendEmptyMessage(REPORT_WINDOWS_CHANGE); 177 } 178 } catch (RuntimeException e) { 179 mInLayout = false; 180 Slog.wtf(TAG, "Unhandled exception while laying out windows", e); 181 } 182 183 Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); 184 } 185 debugLayoutRepeats(final String msg, int pendingLayoutChanges)186 void debugLayoutRepeats(final String msg, int pendingLayoutChanges) { 187 if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) { 188 Slog.v(TAG, "Layouts looping: " + msg + 189 ", mPendingLayoutChanges = 0x" + Integer.toHexString(pendingLayoutChanges)); 190 } 191 } 192 isInLayout()193 boolean isInLayout() { 194 return mInLayout; 195 } 196 requestTraversal()197 void requestTraversal() { 198 if (!mTraversalScheduled) { 199 mTraversalScheduled = true; 200 mService.mAnimationHandler.post(mPerformSurfacePlacement); 201 } 202 } 203 dump(PrintWriter pw, String prefix)204 public void dump(PrintWriter pw, String prefix) { 205 pw.println(prefix + "mTraversalScheduled=" + mTraversalScheduled); 206 pw.println(prefix + "mHoldScreenWindow=" + mService.mRoot.mHoldScreenWindow); 207 pw.println(prefix + "mObscuringWindow=" + mService.mRoot.mObscuringWindow); 208 } 209 } 210