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