1 /*
2  * Copyright (C) 2015 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.os.Trace.TRACE_TAG_WINDOW_MANAGER;
20 import static android.view.Surface.SCALING_MODE_SCALE_TO_WINDOW;
21 import static android.view.SurfaceControl.METADATA_OWNER_UID;
22 import static android.view.SurfaceControl.METADATA_WINDOW_TYPE;
23 
24 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
25 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
26 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
27 import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
28 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
29 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
30 import static com.android.server.wm.WindowSurfaceControllerProto.LAYER;
31 import static com.android.server.wm.WindowSurfaceControllerProto.SHOWN;
32 
33 import android.graphics.Rect;
34 import android.graphics.Region;
35 import android.os.Debug;
36 import android.os.IBinder;
37 import android.os.Trace;
38 import android.util.Slog;
39 import android.util.proto.ProtoOutputStream;
40 import android.view.SurfaceControl;
41 import android.view.SurfaceSession;
42 import android.view.WindowContentFrameStats;
43 
44 import java.io.PrintWriter;
45 
46 class WindowSurfaceController {
47     static final String TAG = TAG_WITH_CLASS_NAME ? "WindowSurfaceController" : TAG_WM;
48 
49     final WindowStateAnimator mAnimator;
50 
51     SurfaceControl mSurfaceControl;
52 
53     // Should only be set from within setShown().
54     private boolean mSurfaceShown = false;
55     private float mSurfaceX = 0;
56     private float mSurfaceY = 0;
57     private int mSurfaceW = 0;
58     private int mSurfaceH = 0;
59     private Rect mSurfaceCrop = new Rect(0, 0, -1, -1);
60 
61     // Initialize to the identity matrix.
62     private float mLastDsdx = 1;
63     private float mLastDtdx = 0;
64     private float mLastDsdy = 0;
65     private float mLastDtdy = 1;
66 
67     private float mSurfaceAlpha = 0;
68 
69     private int mSurfaceLayer = 0;
70 
71     // Surface flinger doesn't support crop rectangles where width or height is non-positive.
72     // However, we need to somehow handle the situation where the cropping would completely hide
73     // the window. We achieve this by explicitly hiding the surface and not letting it be shown.
74     private boolean mHiddenForCrop = false;
75 
76     // Initially a surface is hidden after just being created.
77     private boolean mHiddenForOtherReasons = true;
78     private final String title;
79 
80     private final WindowManagerService mService;
81 
82     private final int mWindowType;
83     private final Session mWindowSession;
84 
85     private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
86 
WindowSurfaceController(SurfaceSession s, String name, int w, int h, int format, int flags, WindowStateAnimator animator, int windowType, int ownerUid)87     public WindowSurfaceController(SurfaceSession s, String name, int w, int h, int format,
88             int flags, WindowStateAnimator animator, int windowType, int ownerUid) {
89         mAnimator = animator;
90 
91         mSurfaceW = w;
92         mSurfaceH = h;
93 
94         title = name;
95 
96         mService = animator.mService;
97         final WindowState win = animator.mWin;
98         mWindowType = windowType;
99         mWindowSession = win.mSession;
100 
101         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "new SurfaceControl");
102         final SurfaceControl.Builder b = win.makeSurface()
103                 .setParent(win.getSurfaceControl())
104                 .setName(name)
105                 .setBufferSize(w, h)
106                 .setFormat(format)
107                 .setFlags(flags)
108                 .setMetadata(METADATA_WINDOW_TYPE, windowType)
109                 .setMetadata(METADATA_OWNER_UID, ownerUid);
110         mSurfaceControl = b.build();
111         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
112     }
113 
logSurface(String msg, RuntimeException where)114     private void logSurface(String msg, RuntimeException where) {
115         String str = "  SURFACE " + msg + ": " + title;
116         if (where != null) {
117             Slog.i(TAG, str, where);
118         } else {
119             Slog.i(TAG, str);
120         }
121     }
122 
reparentChildrenInTransaction(WindowSurfaceController other)123     void reparentChildrenInTransaction(WindowSurfaceController other) {
124         if (SHOW_TRANSACTIONS) Slog.i(TAG, "REPARENT from: " + this + " to: " + other);
125         if ((mSurfaceControl != null) && (other.mSurfaceControl != null)) {
126             mSurfaceControl.reparentChildren(other.getHandle());
127         }
128     }
129 
detachChildren()130     void detachChildren() {
131         if (SHOW_TRANSACTIONS) Slog.i(TAG, "SEVER CHILDREN");
132         if (mSurfaceControl != null) {
133             mSurfaceControl.detachChildren();
134         }
135     }
136 
hide(SurfaceControl.Transaction transaction, String reason)137     void hide(SurfaceControl.Transaction transaction, String reason) {
138         if (SHOW_TRANSACTIONS) logSurface("HIDE ( " + reason + " )", null);
139         mHiddenForOtherReasons = true;
140 
141         mAnimator.destroyPreservedSurfaceLocked();
142         if (mSurfaceShown) {
143             hideSurface(transaction);
144         }
145     }
146 
hideSurface(SurfaceControl.Transaction transaction)147     private void hideSurface(SurfaceControl.Transaction transaction) {
148         if (mSurfaceControl == null) {
149             return;
150         }
151         setShown(false);
152         try {
153             transaction.hide(mSurfaceControl);
154         } catch (RuntimeException e) {
155             Slog.w(TAG, "Exception hiding surface in " + this);
156         }
157     }
158 
destroyNotInTransaction()159     void destroyNotInTransaction() {
160         if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
161             Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(8));
162         }
163         try {
164             if (mSurfaceControl != null) {
165                 mTmpTransaction.remove(mSurfaceControl).apply();
166             }
167         } catch (RuntimeException e) {
168             Slog.w(TAG, "Error destroying surface in: " + this, e);
169         } finally {
170             setShown(false);
171             mSurfaceControl = null;
172         }
173     }
174 
setCropInTransaction(Rect clipRect, boolean recoveringMemory)175     void setCropInTransaction(Rect clipRect, boolean recoveringMemory) {
176         if (SHOW_TRANSACTIONS) logSurface(
177                 "CROP " + clipRect.toShortString(), null);
178         try {
179             if (clipRect.width() > 0 && clipRect.height() > 0) {
180                 if (!clipRect.equals(mSurfaceCrop)) {
181                     mSurfaceControl.setWindowCrop(clipRect);
182                     mSurfaceCrop.set(clipRect);
183                 }
184                 mHiddenForCrop = false;
185                 updateVisibility();
186             } else {
187                 mHiddenForCrop = true;
188                 mAnimator.destroyPreservedSurfaceLocked();
189                 updateVisibility();
190             }
191         } catch (RuntimeException e) {
192             Slog.w(TAG, "Error setting crop surface of " + this
193                     + " crop=" + clipRect.toShortString(), e);
194             if (!recoveringMemory) {
195                 mAnimator.reclaimSomeSurfaceMemory("crop", true);
196             }
197         }
198     }
199 
clearCropInTransaction(boolean recoveringMemory)200     void clearCropInTransaction(boolean recoveringMemory) {
201         if (SHOW_TRANSACTIONS) logSurface(
202                 "CLEAR CROP", null);
203         try {
204             Rect clipRect = new Rect(0, 0, -1, -1);
205             if (mSurfaceCrop.equals(clipRect)) {
206                 return;
207             }
208             mSurfaceControl.setWindowCrop(clipRect);
209             mSurfaceCrop.set(clipRect);
210         } catch (RuntimeException e) {
211             Slog.w(TAG, "Error setting clearing crop of " + this, e);
212             if (!recoveringMemory) {
213                 mAnimator.reclaimSomeSurfaceMemory("crop", true);
214             }
215         }
216     }
217 
setPositionInTransaction(float left, float top, boolean recoveringMemory)218     void setPositionInTransaction(float left, float top, boolean recoveringMemory) {
219         setPosition(null, left, top, recoveringMemory);
220     }
221 
setPosition(SurfaceControl.Transaction t, float left, float top, boolean recoveringMemory)222     void setPosition(SurfaceControl.Transaction t, float left, float top,
223             boolean recoveringMemory) {
224         final boolean surfaceMoved = mSurfaceX != left || mSurfaceY != top;
225         if (surfaceMoved) {
226             mSurfaceX = left;
227             mSurfaceY = top;
228 
229             try {
230                 if (SHOW_TRANSACTIONS) logSurface(
231                         "POS (setPositionInTransaction) @ (" + left + "," + top + ")", null);
232 
233                 if (t == null) {
234                     mSurfaceControl.setPosition(left, top);
235                 } else {
236                     t.setPosition(mSurfaceControl, left, top);
237                 }
238             } catch (RuntimeException e) {
239                 Slog.w(TAG, "Error positioning surface of " + this
240                         + " pos=(" + left + "," + top + ")", e);
241                 if (!recoveringMemory) {
242                     mAnimator.reclaimSomeSurfaceMemory("position", true);
243                 }
244             }
245         }
246     }
247 
setGeometryAppliesWithResizeInTransaction(boolean recoveringMemory)248     void setGeometryAppliesWithResizeInTransaction(boolean recoveringMemory) {
249         mSurfaceControl.setGeometryAppliesWithResize();
250     }
251 
setMatrixInTransaction(float dsdx, float dtdx, float dtdy, float dsdy, boolean recoveringMemory)252     void setMatrixInTransaction(float dsdx, float dtdx, float dtdy, float dsdy,
253             boolean recoveringMemory) {
254         setMatrix(null, dsdx, dtdx, dtdy, dsdy, false);
255     }
256 
setMatrix(SurfaceControl.Transaction t, float dsdx, float dtdx, float dtdy, float dsdy, boolean recoveringMemory)257     void setMatrix(SurfaceControl.Transaction t, float dsdx, float dtdx,
258             float dtdy, float dsdy, boolean recoveringMemory) {
259         final boolean matrixChanged = mLastDsdx != dsdx || mLastDtdx != dtdx ||
260                                       mLastDtdy != dtdy || mLastDsdy != dsdy;
261         if (!matrixChanged) {
262             return;
263         }
264 
265         mLastDsdx = dsdx;
266         mLastDtdx = dtdx;
267         mLastDtdy = dtdy;
268         mLastDsdy = dsdy;
269 
270         try {
271             if (SHOW_TRANSACTIONS) logSurface(
272                     "MATRIX [" + dsdx + "," + dtdx + "," + dtdy + "," + dsdy + "]", null);
273             if (t == null) {
274                 mSurfaceControl.setMatrix(dsdx, dtdx, dtdy, dsdy);
275             } else {
276                 t.setMatrix(mSurfaceControl, dsdx, dtdx, dtdy, dsdy);
277             }
278         } catch (RuntimeException e) {
279             // If something goes wrong with the surface (such
280             // as running out of memory), don't take down the
281             // entire system.
282             Slog.e(TAG, "Error setting matrix on surface surface" + title
283                     + " MATRIX [" + dsdx + "," + dtdx + "," + dtdy + "," + dsdy + "]", null);
284             if (!recoveringMemory) {
285                 mAnimator.reclaimSomeSurfaceMemory("matrix", true);
286             }
287         }
288     }
289 
setBufferSizeInTransaction(int width, int height, boolean recoveringMemory)290     boolean setBufferSizeInTransaction(int width, int height, boolean recoveringMemory) {
291         final boolean surfaceResized = mSurfaceW != width || mSurfaceH != height;
292         if (surfaceResized) {
293             mSurfaceW = width;
294             mSurfaceH = height;
295 
296             try {
297                 if (SHOW_TRANSACTIONS) logSurface(
298                         "SIZE " + width + "x" + height, null);
299                 mSurfaceControl.setBufferSize(width, height);
300             } catch (RuntimeException e) {
301                 // If something goes wrong with the surface (such
302                 // as running out of memory), don't take down the
303                 // entire system.
304                 Slog.e(TAG, "Error resizing surface of " + title
305                         + " size=(" + width + "x" + height + ")", e);
306                 if (!recoveringMemory) {
307                     mAnimator.reclaimSomeSurfaceMemory("size", true);
308                 }
309                 return false;
310             }
311             return true;
312         }
313         return false;
314     }
315 
prepareToShowInTransaction(float alpha, float dsdx, float dtdx, float dsdy, float dtdy, boolean recoveringMemory)316     boolean prepareToShowInTransaction(float alpha,
317             float dsdx, float dtdx, float dsdy,
318             float dtdy, boolean recoveringMemory) {
319         if (mSurfaceControl != null) {
320             try {
321                 mSurfaceAlpha = alpha;
322                 mSurfaceControl.setAlpha(alpha);
323                 mLastDsdx = dsdx;
324                 mLastDtdx = dtdx;
325                 mLastDsdy = dsdy;
326                 mLastDtdy = dtdy;
327                 mSurfaceControl.setMatrix(
328                         dsdx, dtdx, dsdy, dtdy);
329             } catch (RuntimeException e) {
330                 Slog.w(TAG, "Error updating surface in " + title, e);
331                 if (!recoveringMemory) {
332                     mAnimator.reclaimSomeSurfaceMemory("update", true);
333                 }
334                 return false;
335             }
336         }
337         return true;
338     }
339 
setTransparentRegionHint(final Region region)340     void setTransparentRegionHint(final Region region) {
341         if (mSurfaceControl == null) {
342             Slog.w(TAG, "setTransparentRegionHint: null mSurface after mHasSurface true");
343             return;
344         }
345         if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setTransparentRegion");
346         mService.openSurfaceTransaction();
347         try {
348             mSurfaceControl.setTransparentRegionHint(region);
349         } finally {
350             mService.closeSurfaceTransaction("setTransparentRegion");
351             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
352                     "<<< CLOSE TRANSACTION setTransparentRegion");
353         }
354     }
355 
setOpaque(boolean isOpaque)356     void setOpaque(boolean isOpaque) {
357         if (SHOW_TRANSACTIONS) logSurface("isOpaque=" + isOpaque,
358                 null);
359 
360         if (mSurfaceControl == null) {
361             return;
362         }
363         if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setOpaqueLocked");
364         mService.openSurfaceTransaction();
365         try {
366             mSurfaceControl.setOpaque(isOpaque);
367         } finally {
368             mService.closeSurfaceTransaction("setOpaqueLocked");
369             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION setOpaqueLocked");
370         }
371     }
372 
setSecure(boolean isSecure)373     void setSecure(boolean isSecure) {
374         if (SHOW_TRANSACTIONS) logSurface("isSecure=" + isSecure,
375                 null);
376 
377         if (mSurfaceControl == null) {
378             return;
379         }
380         if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setSecureLocked");
381         mService.openSurfaceTransaction();
382         try {
383             mSurfaceControl.setSecure(isSecure);
384         } finally {
385             mService.closeSurfaceTransaction("setSecure");
386             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION setSecureLocked");
387         }
388     }
389 
setColorSpaceAgnostic(boolean agnostic)390     void setColorSpaceAgnostic(boolean agnostic) {
391         if (SHOW_TRANSACTIONS) {
392             logSurface("isColorSpaceAgnostic=" + agnostic, null);
393         }
394 
395         if (mSurfaceControl == null) {
396             return;
397         }
398         if (SHOW_LIGHT_TRANSACTIONS) {
399             Slog.i(TAG, ">>> OPEN TRANSACTION setColorSpaceAgnosticLocked");
400         }
401         mService.openSurfaceTransaction();
402         try {
403             mSurfaceControl.setColorSpaceAgnostic(agnostic);
404         } finally {
405             mService.closeSurfaceTransaction("setColorSpaceAgnostic");
406             if (SHOW_LIGHT_TRANSACTIONS) {
407                 Slog.i(TAG, "<<< CLOSE TRANSACTION setColorSpaceAgnosticLocked");
408             }
409         }
410     }
411 
getContainerRect(Rect rect)412     void getContainerRect(Rect rect) {
413         mAnimator.getContainerRect(rect);
414     }
415 
showRobustlyInTransaction()416     boolean showRobustlyInTransaction() {
417         if (SHOW_TRANSACTIONS) logSurface(
418                 "SHOW (performLayout)", null);
419         if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + this
420                 + " during relayout");
421         mHiddenForOtherReasons = false;
422         return updateVisibility();
423     }
424 
updateVisibility()425     private boolean updateVisibility() {
426         if (mHiddenForCrop || mHiddenForOtherReasons) {
427             if (mSurfaceShown) {
428                 hideSurface(mTmpTransaction);
429                 SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
430             }
431             return false;
432         } else {
433             if (!mSurfaceShown) {
434                 return showSurface();
435             } else {
436                 return true;
437             }
438         }
439     }
440 
showSurface()441     private boolean showSurface() {
442         try {
443             setShown(true);
444             mSurfaceControl.show();
445             return true;
446         } catch (RuntimeException e) {
447             Slog.w(TAG, "Failure showing surface " + mSurfaceControl + " in " + this, e);
448         }
449 
450         mAnimator.reclaimSomeSurfaceMemory("show", true);
451 
452         return false;
453     }
454 
deferTransactionUntil(IBinder handle, long frame)455     void deferTransactionUntil(IBinder handle, long frame) {
456         // TODO: Logging
457         mSurfaceControl.deferTransactionUntil(handle, frame);
458     }
459 
forceScaleableInTransaction(boolean force)460     void forceScaleableInTransaction(boolean force) {
461         // -1 means we don't override the default or client specified
462         // scaling mode.
463         int scalingMode = force ? SCALING_MODE_SCALE_TO_WINDOW : -1;
464         mSurfaceControl.setOverrideScalingMode(scalingMode);
465     }
466 
clearWindowContentFrameStats()467     boolean clearWindowContentFrameStats() {
468         if (mSurfaceControl == null) {
469             return false;
470         }
471         return mSurfaceControl.clearContentFrameStats();
472     }
473 
getWindowContentFrameStats(WindowContentFrameStats outStats)474     boolean getWindowContentFrameStats(WindowContentFrameStats outStats) {
475         if (mSurfaceControl == null) {
476             return false;
477         }
478         return mSurfaceControl.getContentFrameStats(outStats);
479     }
480 
481 
hasSurface()482     boolean hasSurface() {
483         return mSurfaceControl != null;
484     }
485 
getHandle()486     IBinder getHandle() {
487         if (mSurfaceControl == null) {
488             return null;
489         }
490         return mSurfaceControl.getHandle();
491     }
492 
getSurfaceControl(SurfaceControl outSurfaceControl)493     void getSurfaceControl(SurfaceControl outSurfaceControl) {
494         outSurfaceControl.copyFrom(mSurfaceControl);
495     }
496 
getLayer()497     int getLayer() {
498         return mSurfaceLayer;
499     }
500 
getShown()501     boolean getShown() {
502         return mSurfaceShown;
503     }
504 
setShown(boolean surfaceShown)505     void setShown(boolean surfaceShown) {
506         mSurfaceShown = surfaceShown;
507 
508         mService.updateNonSystemOverlayWindowsVisibilityIfNeeded(mAnimator.mWin, surfaceShown);
509 
510         mAnimator.mWin.onSurfaceShownChanged(surfaceShown);
511 
512         if (mWindowSession != null) {
513             mWindowSession.onWindowSurfaceVisibilityChanged(this, mSurfaceShown, mWindowType);
514         }
515     }
516 
getX()517     float getX() {
518         return mSurfaceX;
519     }
520 
getY()521     float getY() {
522         return mSurfaceY;
523     }
524 
getWidth()525     int getWidth() {
526         return mSurfaceW;
527     }
528 
getHeight()529     int getHeight() {
530         return mSurfaceH;
531     }
532 
writeToProto(ProtoOutputStream proto, long fieldId)533     void writeToProto(ProtoOutputStream proto, long fieldId) {
534         final long token = proto.start(fieldId);
535         proto.write(SHOWN, mSurfaceShown);
536         proto.write(LAYER, mSurfaceLayer);
537         proto.end(token);
538     }
539 
dump(PrintWriter pw, String prefix, boolean dumpAll)540     public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
541         if (dumpAll) {
542             pw.print(prefix); pw.print("mSurface="); pw.println(mSurfaceControl);
543         }
544         pw.print(prefix); pw.print("Surface: shown="); pw.print(mSurfaceShown);
545         pw.print(" layer="); pw.print(mSurfaceLayer);
546         pw.print(" alpha="); pw.print(mSurfaceAlpha);
547         pw.print(" rect=("); pw.print(mSurfaceX);
548         pw.print(","); pw.print(mSurfaceY);
549         pw.print(") "); pw.print(mSurfaceW);
550         pw.print(" x "); pw.print(mSurfaceH);
551         pw.print(" transform=("); pw.print(mLastDsdx); pw.print(", ");
552         pw.print(mLastDtdx); pw.print(", "); pw.print(mLastDsdy);
553         pw.print(", "); pw.print(mLastDtdy); pw.println(")");
554     }
555 
556     @Override
toString()557     public String toString() {
558         return mSurfaceControl.toString();
559     }
560 }
561