1 /*
2  * Copyright (C) 2007 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 android.view;
18 
19 import static android.system.OsConstants.EINVAL;
20 
21 import android.annotation.FloatRange;
22 import android.annotation.IntDef;
23 import android.annotation.NonNull;
24 import android.compat.annotation.UnsupportedAppUsage;
25 import android.content.res.CompatibilityInfo.Translator;
26 import android.graphics.Canvas;
27 import android.graphics.ColorSpace;
28 import android.graphics.GraphicBuffer;
29 import android.graphics.HardwareRenderer;
30 import android.graphics.Matrix;
31 import android.graphics.RecordingCanvas;
32 import android.graphics.Rect;
33 import android.graphics.RenderNode;
34 import android.graphics.SurfaceTexture;
35 import android.os.Parcel;
36 import android.os.Parcelable;
37 import android.util.Log;
38 
39 import dalvik.system.CloseGuard;
40 
41 import java.lang.annotation.Retention;
42 import java.lang.annotation.RetentionPolicy;
43 
44 /**
45  * Handle onto a raw buffer that is being managed by the screen compositor.
46  *
47  * <p>A Surface is generally created by or from a consumer of image buffers (such as a
48  * {@link android.graphics.SurfaceTexture}, {@link android.media.MediaRecorder}, or
49  * {@link android.renderscript.Allocation}), and is handed to some kind of producer (such as
50  * {@link android.opengl.EGL14#eglCreateWindowSurface(android.opengl.EGLDisplay,android.opengl.EGLConfig,java.lang.Object,int[],int) OpenGL},
51  * {@link android.media.MediaPlayer#setSurface MediaPlayer}, or
52  * {@link android.hardware.camera2.CameraDevice#createCaptureSession CameraDevice}) to draw
53  * into.</p>
54  *
55  * <p><strong>Note:</strong> A Surface acts like a
56  * {@link java.lang.ref.WeakReference weak reference} to the consumer it is associated with. By
57  * itself it will not keep its parent consumer from being reclaimed.</p>
58  */
59 public class Surface implements Parcelable {
60     private static final String TAG = "Surface";
61 
nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture)62     private static native long nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture)
63             throws OutOfResourcesException;
64 
nativeCreateFromSurfaceControl(long surfaceControlNativeObject)65     private static native long nativeCreateFromSurfaceControl(long surfaceControlNativeObject);
nativeGetFromSurfaceControl(long surfaceObject, long surfaceControlNativeObject)66     private static native long nativeGetFromSurfaceControl(long surfaceObject,
67             long surfaceControlNativeObject);
68 
nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty)69     private static native long nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty)
70             throws OutOfResourcesException;
nativeUnlockCanvasAndPost(long nativeObject, Canvas canvas)71     private static native void nativeUnlockCanvasAndPost(long nativeObject, Canvas canvas);
72 
73     @UnsupportedAppUsage
nativeRelease(long nativeObject)74     private static native void nativeRelease(long nativeObject);
nativeIsValid(long nativeObject)75     private static native boolean nativeIsValid(long nativeObject);
nativeIsConsumerRunningBehind(long nativeObject)76     private static native boolean nativeIsConsumerRunningBehind(long nativeObject);
nativeReadFromParcel(long nativeObject, Parcel source)77     private static native long nativeReadFromParcel(long nativeObject, Parcel source);
nativeWriteToParcel(long nativeObject, Parcel dest)78     private static native void nativeWriteToParcel(long nativeObject, Parcel dest);
79 
nativeAllocateBuffers(long nativeObject)80     private static native void nativeAllocateBuffers(long nativeObject);
81 
nativeGetWidth(long nativeObject)82     private static native int nativeGetWidth(long nativeObject);
nativeGetHeight(long nativeObject)83     private static native int nativeGetHeight(long nativeObject);
84 
nativeGetNextFrameNumber(long nativeObject)85     private static native long nativeGetNextFrameNumber(long nativeObject);
nativeSetScalingMode(long nativeObject, int scalingMode)86     private static native int nativeSetScalingMode(long nativeObject, int scalingMode);
nativeForceScopedDisconnect(long nativeObject)87     private static native int nativeForceScopedDisconnect(long nativeObject);
nativeAttachAndQueueBufferWithColorSpace(long nativeObject, GraphicBuffer buffer, int colorSpaceId)88     private static native int nativeAttachAndQueueBufferWithColorSpace(long nativeObject,
89             GraphicBuffer buffer, int colorSpaceId);
90 
nativeSetSharedBufferModeEnabled(long nativeObject, boolean enabled)91     private static native int nativeSetSharedBufferModeEnabled(long nativeObject, boolean enabled);
nativeSetAutoRefreshEnabled(long nativeObject, boolean enabled)92     private static native int nativeSetAutoRefreshEnabled(long nativeObject, boolean enabled);
93 
nativeSetFrameRate( long nativeObject, float frameRate, int compatibility)94     private static native int nativeSetFrameRate(
95             long nativeObject, float frameRate, int compatibility);
96 
97     public static final @android.annotation.NonNull Parcelable.Creator<Surface> CREATOR =
98             new Parcelable.Creator<Surface>() {
99         @Override
100         public Surface createFromParcel(Parcel source) {
101             try {
102                 Surface s = new Surface();
103                 s.readFromParcel(source);
104                 return s;
105             } catch (Exception e) {
106                 Log.e(TAG, "Exception creating surface from parcel", e);
107                 return null;
108             }
109         }
110 
111         @Override
112         public Surface[] newArray(int size) {
113             return new Surface[size];
114         }
115     };
116 
117     private final CloseGuard mCloseGuard = CloseGuard.get();
118 
119     // Guarded state.
120     @UnsupportedAppUsage
121     final Object mLock = new Object(); // protects the native state
122     @UnsupportedAppUsage
123     private String mName;
124     @UnsupportedAppUsage
125     long mNativeObject; // package scope only for SurfaceControl access
126     @UnsupportedAppUsage
127     private long mLockedObject;
128     private int mGenerationId; // incremented each time mNativeObject changes
129     private final Canvas mCanvas = new CompatibleCanvas();
130 
131     // A matrix to scale the matrix set by application. This is set to null for
132     // non compatibility mode.
133     private Matrix mCompatibleMatrix;
134 
135     private HwuiContext mHwuiContext;
136 
137     private boolean mIsSingleBuffered;
138     private boolean mIsSharedBufferModeEnabled;
139     private boolean mIsAutoRefreshEnabled;
140 
141     /** @hide */
142     @Retention(RetentionPolicy.SOURCE)
143     @IntDef(prefix = { "SCALING_MODE_" }, value = {
144             SCALING_MODE_FREEZE,
145             SCALING_MODE_SCALE_TO_WINDOW,
146             SCALING_MODE_SCALE_CROP,
147             SCALING_MODE_NO_SCALE_CROP
148     })
149     public @interface ScalingMode {}
150     // From system/window.h
151     /** @hide */
152     public static final int SCALING_MODE_FREEZE = 0;
153     /** @hide */
154     public static final int SCALING_MODE_SCALE_TO_WINDOW = 1;
155     /** @hide */
156     public static final int SCALING_MODE_SCALE_CROP = 2;
157     /** @hide */
158     public static final int SCALING_MODE_NO_SCALE_CROP = 3;
159 
160     /** @hide */
161     @IntDef(prefix = { "ROTATION_" }, value = {
162             ROTATION_0,
163             ROTATION_90,
164             ROTATION_180,
165             ROTATION_270
166     })
167     @Retention(RetentionPolicy.SOURCE)
168     public @interface Rotation {}
169 
170     /**
171      * Rotation constant: 0 degree rotation (natural orientation)
172      */
173     public static final int ROTATION_0 = 0;
174 
175     /**
176      * Rotation constant: 90 degree rotation.
177      */
178     public static final int ROTATION_90 = 1;
179 
180     /**
181      * Rotation constant: 180 degree rotation.
182      */
183     public static final int ROTATION_180 = 2;
184 
185     /**
186      * Rotation constant: 270 degree rotation.
187      */
188     public static final int ROTATION_270 = 3;
189 
190     /** @hide */
191     @Retention(RetentionPolicy.SOURCE)
192     @IntDef(prefix = {"FRAME_RATE_COMPATIBILITY_"},
193             value = {FRAME_RATE_COMPATIBILITY_DEFAULT, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE})
194     public @interface FrameRateCompatibility {}
195 
196     // From native_window.h. Keep these in sync.
197     /**
198      * There are no inherent restrictions on the frame rate of this surface. When the
199      * system selects a frame rate other than what the app requested, the app will be able
200      * to run at the system frame rate without requiring pull down. This value should be
201      * used when displaying game content, UIs, and anything that isn't video.
202      */
203     public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0;
204 
205     /**
206      * This surface is being used to display content with an inherently fixed frame rate,
207      * e.g. a video that has a specific frame rate. When the system selects a frame rate
208      * other than what the app requested, the app will need to do pull down or use some
209      * other technique to adapt to the system's frame rate. The user experience is likely
210      * to be worse (e.g. more frame stuttering) than it would be if the system had chosen
211      * the app's requested frame rate. This value should be used for video content.
212      */
213     public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1;
214 
215     /**
216      * Create an empty surface, which will later be filled in by readFromParcel().
217      * @hide
218      */
219     @UnsupportedAppUsage
Surface()220     public Surface() {
221     }
222 
223     /**
224      * Create a Surface assosciated with a given {@link SurfaceControl}. Buffers submitted to this
225      * surface will be displayed by the system compositor according to the parameters
226      * specified by the control. Multiple surfaces may be constructed from one SurfaceControl,
227      * but only one can be connected (e.g. have an active EGL context) at a time.
228      *
229      * @param from The SurfaceControl to assosciate this Surface with
230      */
Surface(@onNull SurfaceControl from)231     public Surface(@NonNull SurfaceControl from) {
232         copyFrom(from);
233     }
234 
235     /**
236      * Create Surface from a {@link SurfaceTexture}.
237      *
238      * Images drawn to the Surface will be made available to the {@link
239      * SurfaceTexture}, which can attach them to an OpenGL ES texture via {@link
240      * SurfaceTexture#updateTexImage}.
241      *
242      * Please note that holding onto the Surface created here is not enough to
243      * keep the provided SurfaceTexture from being reclaimed.  In that sense,
244      * the Surface will act like a
245      * {@link java.lang.ref.WeakReference weak reference} to the SurfaceTexture.
246      *
247      * @param surfaceTexture The {@link SurfaceTexture} that is updated by this
248      * Surface.
249      * @throws OutOfResourcesException if the surface could not be created.
250      */
Surface(SurfaceTexture surfaceTexture)251     public Surface(SurfaceTexture surfaceTexture) {
252         if (surfaceTexture == null) {
253             throw new IllegalArgumentException("surfaceTexture must not be null");
254         }
255         mIsSingleBuffered = surfaceTexture.isSingleBuffered();
256         synchronized (mLock) {
257             mName = surfaceTexture.toString();
258             setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
259         }
260     }
261 
262     /* called from android_view_Surface_createFromIGraphicBufferProducer() */
263     @UnsupportedAppUsage
Surface(long nativeObject)264     private Surface(long nativeObject) {
265         synchronized (mLock) {
266             setNativeObjectLocked(nativeObject);
267         }
268     }
269 
270     @Override
finalize()271     protected void finalize() throws Throwable {
272         try {
273             if (mCloseGuard != null) {
274                 mCloseGuard.warnIfOpen();
275             }
276             release();
277         } finally {
278             super.finalize();
279         }
280     }
281 
282     /**
283      * Release the local reference to the server-side surface.
284      * Always call release() when you're done with a Surface.
285      * This will make the surface invalid.
286      */
release()287     public void release() {
288         synchronized (mLock) {
289             if (mHwuiContext != null) {
290                 mHwuiContext.destroy();
291                 mHwuiContext = null;
292             }
293             if (mNativeObject != 0) {
294                 nativeRelease(mNativeObject);
295                 setNativeObjectLocked(0);
296             }
297         }
298     }
299 
300     /**
301      * Free all server-side state associated with this surface and
302      * release this object's reference.  This method can only be
303      * called from the process that created the service.
304      * @hide
305      */
306     @UnsupportedAppUsage
destroy()307     public void destroy() {
308         release();
309     }
310 
311     /**
312      * Destroys the HwuiContext without completely
313      * releasing the Surface.
314      * @hide
315      */
hwuiDestroy()316     public void hwuiDestroy() {
317         if (mHwuiContext != null) {
318             mHwuiContext.destroy();
319             mHwuiContext = null;
320         }
321     }
322 
323     /**
324      * Returns true if this object holds a valid surface.
325      *
326      * @return True if it holds a physical surface, so lockCanvas() will succeed.
327      * Otherwise returns false.
328      */
isValid()329     public boolean isValid() {
330         synchronized (mLock) {
331             if (mNativeObject == 0) return false;
332             return nativeIsValid(mNativeObject);
333         }
334     }
335 
336     /**
337      * Gets the generation number of this surface, incremented each time
338      * the native surface contained within this object changes.
339      *
340      * @return The current generation number.
341      * @hide
342      */
getGenerationId()343     public int getGenerationId() {
344         synchronized (mLock) {
345             return mGenerationId;
346         }
347     }
348 
349     /**
350      * Returns the next frame number which will be dequeued for rendering.
351      * Intended for use with SurfaceFlinger's deferred transactions API.
352      *
353      * @hide
354      */
355     @UnsupportedAppUsage
getNextFrameNumber()356     public long getNextFrameNumber() {
357         synchronized (mLock) {
358             checkNotReleasedLocked();
359             return nativeGetNextFrameNumber(mNativeObject);
360         }
361     }
362 
363     /**
364      * Returns true if the consumer of this Surface is running behind the producer.
365      *
366      * @return True if the consumer is more than one buffer ahead of the producer.
367      * @hide
368      */
isConsumerRunningBehind()369     public boolean isConsumerRunningBehind() {
370         synchronized (mLock) {
371             checkNotReleasedLocked();
372             return nativeIsConsumerRunningBehind(mNativeObject);
373         }
374     }
375 
376     /**
377      * Gets a {@link Canvas} for drawing into this surface.
378      *
379      * After drawing into the provided {@link Canvas}, the caller must
380      * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
381      *
382      * @param inOutDirty A rectangle that represents the dirty region that the caller wants
383      * to redraw.  This function may choose to expand the dirty rectangle if for example
384      * the surface has been resized or if the previous contents of the surface were
385      * not available.  The caller must redraw the entire dirty region as represented
386      * by the contents of the inOutDirty rectangle upon return from this function.
387      * The caller may also pass <code>null</code> instead, in the case where the
388      * entire surface should be redrawn.
389      * @return A canvas for drawing into the surface.
390      *
391      * @throws IllegalArgumentException If the inOutDirty rectangle is not valid.
392      * @throws OutOfResourcesException If the canvas cannot be locked.
393      */
lockCanvas(Rect inOutDirty)394     public Canvas lockCanvas(Rect inOutDirty)
395             throws Surface.OutOfResourcesException, IllegalArgumentException {
396         synchronized (mLock) {
397             checkNotReleasedLocked();
398             if (mLockedObject != 0) {
399                 // Ideally, nativeLockCanvas() would throw in this situation and prevent the
400                 // double-lock, but that won't happen if mNativeObject was updated.  We can't
401                 // abandon the old mLockedObject because it might still be in use, so instead
402                 // we just refuse to re-lock the Surface.
403                 throw new IllegalArgumentException("Surface was already locked");
404             }
405             mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);
406             return mCanvas;
407         }
408     }
409 
410     /**
411      * Posts the new contents of the {@link Canvas} to the surface and
412      * releases the {@link Canvas}.
413      *
414      * @param canvas The canvas previously obtained from {@link #lockCanvas}.
415      */
unlockCanvasAndPost(Canvas canvas)416     public void unlockCanvasAndPost(Canvas canvas) {
417         synchronized (mLock) {
418             checkNotReleasedLocked();
419 
420             if (mHwuiContext != null) {
421                 mHwuiContext.unlockAndPost(canvas);
422             } else {
423                 unlockSwCanvasAndPost(canvas);
424             }
425         }
426     }
427 
unlockSwCanvasAndPost(Canvas canvas)428     private void unlockSwCanvasAndPost(Canvas canvas) {
429         if (canvas != mCanvas) {
430             throw new IllegalArgumentException("canvas object must be the same instance that "
431                     + "was previously returned by lockCanvas");
432         }
433         if (mNativeObject != mLockedObject) {
434             Log.w(TAG, "WARNING: Surface's mNativeObject (0x" +
435                     Long.toHexString(mNativeObject) + ") != mLockedObject (0x" +
436                     Long.toHexString(mLockedObject) +")");
437         }
438         if (mLockedObject == 0) {
439             throw new IllegalStateException("Surface was not locked");
440         }
441         try {
442             nativeUnlockCanvasAndPost(mLockedObject, canvas);
443         } finally {
444             nativeRelease(mLockedObject);
445             mLockedObject = 0;
446         }
447     }
448 
449     /**
450      * Gets a {@link Canvas} for drawing into this surface.
451      *
452      * After drawing into the provided {@link Canvas}, the caller must
453      * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
454      *
455      * Unlike {@link #lockCanvas(Rect)} this will return a hardware-accelerated
456      * canvas. See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported">
457      * unsupported drawing operations</a> for a list of what is and isn't
458      * supported in a hardware-accelerated canvas. It is also required to
459      * fully cover the surface every time {@link #lockHardwareCanvas()} is
460      * called as the buffer is not preserved between frames. Partial updates
461      * are not supported.
462      *
463      * @return A canvas for drawing into the surface.
464      *
465      * @throws IllegalStateException If the canvas cannot be locked.
466      */
lockHardwareCanvas()467     public Canvas lockHardwareCanvas() {
468         synchronized (mLock) {
469             checkNotReleasedLocked();
470             if (mHwuiContext == null) {
471                 mHwuiContext = new HwuiContext(false);
472             }
473             return mHwuiContext.lockCanvas(
474                     nativeGetWidth(mNativeObject),
475                     nativeGetHeight(mNativeObject));
476         }
477     }
478 
479     /**
480      * Gets a {@link Canvas} for drawing into this surface that supports wide color gamut.
481      *
482      * After drawing into the provided {@link Canvas}, the caller must
483      * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
484      *
485      * Unlike {@link #lockCanvas(Rect)} and {@link #lockHardwareCanvas()},
486      * this will return a hardware-accelerated canvas that supports wide color gamut.
487      * See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported">
488      * unsupported drawing operations</a> for a list of what is and isn't
489      * supported in a hardware-accelerated canvas. It is also required to
490      * fully cover the surface every time {@link #lockHardwareCanvas()} is
491      * called as the buffer is not preserved between frames. Partial updates
492      * are not supported.
493      *
494      * @return A canvas for drawing into the surface.
495      *
496      * @throws IllegalStateException If the canvas cannot be locked.
497      *
498      * @hide
499      */
lockHardwareWideColorGamutCanvas()500     public Canvas lockHardwareWideColorGamutCanvas() {
501         synchronized (mLock) {
502             checkNotReleasedLocked();
503             if (mHwuiContext != null && !mHwuiContext.isWideColorGamut()) {
504                 mHwuiContext.destroy();
505                 mHwuiContext = null;
506             }
507             if (mHwuiContext == null) {
508                 mHwuiContext = new HwuiContext(true);
509             }
510             return mHwuiContext.lockCanvas(
511                     nativeGetWidth(mNativeObject),
512                     nativeGetHeight(mNativeObject));
513         }
514     }
515 
516     /**
517      * @deprecated This API has been removed and is not supported.  Do not use.
518      */
519     @Deprecated
unlockCanvas(Canvas canvas)520     public void unlockCanvas(Canvas canvas) {
521         throw new UnsupportedOperationException();
522     }
523 
524     /**
525      * Sets the translator used to scale canvas's width/height in compatibility
526      * mode.
527      */
setCompatibilityTranslator(Translator translator)528     void setCompatibilityTranslator(Translator translator) {
529         if (translator != null) {
530             float appScale = translator.applicationScale;
531             mCompatibleMatrix = new Matrix();
532             mCompatibleMatrix.setScale(appScale, appScale);
533         }
534     }
535 
536     /**
537      * Copy another surface to this one.  This surface now holds a reference
538      * to the same data as the original surface, and is -not- the owner.
539      * This is for use by the window manager when returning a window surface
540      * back from a client, converting it from the representation being managed
541      * by the window manager to the representation the client uses to draw
542      * in to it.
543      *
544      * @param other {@link SurfaceControl} to copy from.
545      * @hide
546      */
547     @UnsupportedAppUsage
copyFrom(SurfaceControl other)548     public void copyFrom(SurfaceControl other) {
549         if (other == null) {
550             throw new IllegalArgumentException("other must not be null");
551         }
552 
553         long surfaceControlPtr = other.mNativeObject;
554         if (surfaceControlPtr == 0) {
555             throw new NullPointerException(
556                     "null SurfaceControl native object. Are you using a released SurfaceControl?");
557         }
558         long newNativeObject = nativeGetFromSurfaceControl(mNativeObject, surfaceControlPtr);
559 
560         synchronized (mLock) {
561             if (newNativeObject == mNativeObject) {
562                 return;
563             }
564             if (mNativeObject != 0) {
565                 nativeRelease(mNativeObject);
566             }
567             setNativeObjectLocked(newNativeObject);
568         }
569     }
570 
571     /**
572      * Gets a reference a surface created from this one.  This surface now holds a reference
573      * to the same data as the original surface, and is -not- the owner.
574      * This is for use by the window manager when returning a window surface
575      * back from a client, converting it from the representation being managed
576      * by the window manager to the representation the client uses to draw
577      * in to it.
578      *
579      * @param other {@link SurfaceControl} to create surface from.
580      *
581      * @hide
582      */
createFrom(SurfaceControl other)583     public void createFrom(SurfaceControl other) {
584         if (other == null) {
585             throw new IllegalArgumentException("other must not be null");
586         }
587 
588         long surfaceControlPtr = other.mNativeObject;
589         if (surfaceControlPtr == 0) {
590             throw new NullPointerException(
591                     "null SurfaceControl native object. Are you using a released SurfaceControl?");
592         }
593         long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);
594 
595         synchronized (mLock) {
596             if (mNativeObject != 0) {
597                 nativeRelease(mNativeObject);
598             }
599             setNativeObjectLocked(newNativeObject);
600         }
601     }
602 
603     /**
604      * This is intended to be used by {@link SurfaceView#updateWindow} only.
605      * @param other access is not thread safe
606      * @hide
607      * @deprecated
608      */
609     @Deprecated
610     @UnsupportedAppUsage
transferFrom(Surface other)611     public void transferFrom(Surface other) {
612         if (other == null) {
613             throw new IllegalArgumentException("other must not be null");
614         }
615         if (other != this) {
616             final long newPtr;
617             synchronized (other.mLock) {
618                 newPtr = other.mNativeObject;
619                 other.setNativeObjectLocked(0);
620             }
621 
622             synchronized (mLock) {
623                 if (mNativeObject != 0) {
624                     nativeRelease(mNativeObject);
625                 }
626                 setNativeObjectLocked(newPtr);
627             }
628         }
629     }
630 
631     @Override
describeContents()632     public int describeContents() {
633         return 0;
634     }
635 
readFromParcel(Parcel source)636     public void readFromParcel(Parcel source) {
637         if (source == null) {
638             throw new IllegalArgumentException("source must not be null");
639         }
640 
641         synchronized (mLock) {
642             // nativeReadFromParcel() will either return mNativeObject, or
643             // create a new native Surface and return it after reducing
644             // the reference count on mNativeObject.  Either way, it is
645             // not necessary to call nativeRelease() here.
646             // NOTE: This must be kept synchronized with the native parceling code
647             // in frameworks/native/libs/Surface.cpp
648             mName = source.readString();
649             mIsSingleBuffered = source.readInt() != 0;
650             setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
651         }
652     }
653 
654     @Override
writeToParcel(Parcel dest, int flags)655     public void writeToParcel(Parcel dest, int flags) {
656         if (dest == null) {
657             throw new IllegalArgumentException("dest must not be null");
658         }
659         synchronized (mLock) {
660             // NOTE: This must be kept synchronized with the native parceling code
661             // in frameworks/native/libs/Surface.cpp
662             dest.writeString(mName);
663             dest.writeInt(mIsSingleBuffered ? 1 : 0);
664             nativeWriteToParcel(mNativeObject, dest);
665         }
666         if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
667             release();
668         }
669     }
670 
671     @Override
toString()672     public String toString() {
673         synchronized (mLock) {
674             return "Surface(name=" + mName + ")/@0x" +
675                     Integer.toHexString(System.identityHashCode(this));
676         }
677     }
678 
setNativeObjectLocked(long ptr)679     private void setNativeObjectLocked(long ptr) {
680         if (mNativeObject != ptr) {
681             if (mNativeObject == 0 && ptr != 0) {
682                 mCloseGuard.open("release");
683             } else if (mNativeObject != 0 && ptr == 0) {
684                 mCloseGuard.close();
685             }
686             mNativeObject = ptr;
687             mGenerationId += 1;
688             if (mHwuiContext != null) {
689                 mHwuiContext.updateSurface();
690             }
691         }
692     }
693 
checkNotReleasedLocked()694     private void checkNotReleasedLocked() {
695         if (mNativeObject == 0) {
696             throw new IllegalStateException("Surface has already been released.");
697         }
698     }
699 
700     /**
701      * Allocate buffers ahead of time to avoid allocation delays during rendering
702      * @hide
703      */
allocateBuffers()704     public void allocateBuffers() {
705         synchronized (mLock) {
706             checkNotReleasedLocked();
707             nativeAllocateBuffers(mNativeObject);
708         }
709     }
710 
711     /**
712      * Set the scaling mode to be used for this surfaces buffers
713      * @hide
714      */
setScalingMode(@calingMode int scalingMode)715     void setScalingMode(@ScalingMode int scalingMode) {
716         synchronized (mLock) {
717             checkNotReleasedLocked();
718             int err = nativeSetScalingMode(mNativeObject, scalingMode);
719             if (err != 0) {
720                 throw new IllegalArgumentException("Invalid scaling mode: " + scalingMode);
721             }
722         }
723     }
724 
forceScopedDisconnect()725     void forceScopedDisconnect() {
726         synchronized (mLock) {
727             checkNotReleasedLocked();
728             int err = nativeForceScopedDisconnect(mNativeObject);
729             if (err != 0) {
730                 throw new RuntimeException("Failed to disconnect Surface instance (bad object?)");
731             }
732         }
733     }
734 
735     /**
736      * Transfer ownership of buffer with a color space and present it on the Surface.
737      * The supported color spaces are SRGB and Display P3, other color spaces will be
738      * treated as SRGB.
739      * @hide
740      */
attachAndQueueBufferWithColorSpace(GraphicBuffer buffer, ColorSpace colorSpace)741     public void attachAndQueueBufferWithColorSpace(GraphicBuffer buffer, ColorSpace colorSpace) {
742         synchronized (mLock) {
743             checkNotReleasedLocked();
744             if (colorSpace == null) {
745                 colorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
746             }
747             int err = nativeAttachAndQueueBufferWithColorSpace(mNativeObject, buffer,
748                     colorSpace.getId());
749             if (err != 0) {
750                 throw new RuntimeException(
751                         "Failed to attach and queue buffer to Surface (bad object?), "
752                         + "native error: " + err);
753             }
754         }
755     }
756 
757     /**
758      * Deprecated, use attachAndQueueBufferWithColorSpace instead.
759      * Transfer ownership of buffer and present it on the Surface.
760      * The color space of the buffer is treated as SRGB.
761      * @hide
762      */
attachAndQueueBuffer(GraphicBuffer buffer)763     public void attachAndQueueBuffer(GraphicBuffer buffer) {
764         attachAndQueueBufferWithColorSpace(buffer, ColorSpace.get(ColorSpace.Named.SRGB));
765     }
766 
767     /**
768      * Returns whether or not this Surface is backed by a single-buffered SurfaceTexture
769      * @hide
770      */
isSingleBuffered()771     public boolean isSingleBuffered() {
772         return mIsSingleBuffered;
773     }
774 
775     /**
776      * <p>The shared buffer mode allows both the application and the surface compositor
777      * (SurfaceFlinger) to concurrently access this surface's buffer. While the
778      * application is still required to issue a present request
779      * (see {@link #unlockCanvasAndPost(Canvas)}) to the compositor when an update is required,
780      * the compositor may trigger an update at any time. Since the surface's buffer is shared
781      * between the application and the compositor, updates triggered by the compositor may
782      * cause visible tearing.</p>
783      *
784      * <p>The shared buffer mode can be used with
785      * {@link #setAutoRefreshEnabled(boolean) auto-refresh} to avoid the overhead of
786      * issuing present requests.</p>
787      *
788      * <p>If the application uses the shared buffer mode to reduce latency, it is
789      * recommended to use software rendering (see {@link #lockCanvas(Rect)} to ensure
790      * the graphics workloads are not affected by other applications and/or the system
791      * using the GPU. When using software rendering, the application should update the
792      * smallest possible region of the surface required.</p>
793      *
794      * <p class="note">The shared buffer mode might not be supported by the underlying
795      * hardware. Enabling shared buffer mode on hardware that does not support it will
796      * not yield an error but the application will not benefit from lower latency (and
797      * tearing will not be visible).</p>
798      *
799      * <p class="note">Depending on how many and what kind of surfaces are visible, the
800      * surface compositor may need to copy the shared buffer before it is displayed. When
801      * this happens, the latency benefits of shared buffer mode will be reduced.</p>
802      *
803      * @param enabled True to enable the shared buffer mode on this surface, false otherwise
804      *
805      * @see #isSharedBufferModeEnabled()
806      * @see #setAutoRefreshEnabled(boolean)
807      *
808      * @hide
809      */
setSharedBufferModeEnabled(boolean enabled)810     public void setSharedBufferModeEnabled(boolean enabled) {
811         if (mIsSharedBufferModeEnabled != enabled) {
812             int error = nativeSetSharedBufferModeEnabled(mNativeObject, enabled);
813             if (error != 0) {
814                 throw new RuntimeException(
815                         "Failed to set shared buffer mode on Surface (bad object?)");
816             } else {
817                 mIsSharedBufferModeEnabled = enabled;
818             }
819         }
820     }
821 
822     /**
823      * @return True if shared buffer mode is enabled on this surface, false otherwise
824      *
825      * @see #setSharedBufferModeEnabled(boolean)
826      *
827      * @hide
828      */
isSharedBufferModeEnabled()829     public boolean isSharedBufferModeEnabled() {
830         return mIsSharedBufferModeEnabled;
831     }
832 
833     /**
834      * <p>When auto-refresh is enabled, the surface compositor (SurfaceFlinger)
835      * automatically updates the display on a regular refresh cycle. The application
836      * can continue to issue present requests but it is not required. Enabling
837      * auto-refresh may result in visible tearing.</p>
838      *
839      * <p>Auto-refresh has no effect if the {@link #setSharedBufferModeEnabled(boolean)
840      * shared buffer mode} is not enabled.</p>
841      *
842      * <p>Because auto-refresh will trigger continuous updates of the display, it is
843      * recommended to turn it on only when necessary. For example, in a drawing/painting
844      * application auto-refresh should be enabled on finger/pen down and disabled on
845      * finger/pen up.</p>
846      *
847      * @param enabled True to enable auto-refresh on this surface, false otherwise
848      *
849      * @see #isAutoRefreshEnabled()
850      * @see #setSharedBufferModeEnabled(boolean)
851      *
852      * @hide
853      */
setAutoRefreshEnabled(boolean enabled)854     public void setAutoRefreshEnabled(boolean enabled) {
855         if (mIsAutoRefreshEnabled != enabled) {
856             int error = nativeSetAutoRefreshEnabled(mNativeObject, enabled);
857             if (error != 0) {
858                 throw new RuntimeException("Failed to set auto refresh on Surface (bad object?)");
859             } else {
860                 mIsAutoRefreshEnabled = enabled;
861             }
862         }
863     }
864 
865     /**
866      * @return True if auto-refresh is enabled on this surface, false otherwise
867      *
868      * @hide
869      */
isAutoRefreshEnabled()870     public boolean isAutoRefreshEnabled() {
871         return mIsAutoRefreshEnabled;
872     }
873 
874     /**
875      * Sets the intended frame rate for this surface.
876      *
877      * <p>On devices that are capable of running the display at different refresh rates,
878      * the system may choose a display refresh rate to better match this surface's frame
879      * rate. Usage of this API won't introduce frame rate throttling, or affect other
880      * aspects of the application's frame production pipeline. However, because the system
881      * may change the display refresh rate, calls to this function may result in changes
882      * to Choreographer callback timings, and changes to the time interval at which the
883      * system releases buffers back to the application.</p>
884      *
885      * <p>Note that this only has an effect for surfaces presented on the display. If this
886      * surface is consumed by something other than the system compositor, e.g. a media
887      * codec, this call has no effect.</p>
888      *
889      * @param frameRate The intended frame rate of this surface, in frames per second. 0
890      * is a special value that indicates the app will accept the system's choice for the
891      * display frame rate, which is the default behavior if this function isn't
892      * called. The frameRate param does <em>not</em> need to be a valid refresh rate for
893      * this device's display - e.g., it's fine to pass 30fps to a device that can only run
894      * the display at 60fps.
895      *
896      * @param compatibility The frame rate compatibility of this surface. The
897      * compatibility value may influence the system's choice of display frame rate. See
898      * the FRAME_RATE_COMPATIBILITY_* values for more info.
899      *
900      * @throws IllegalArgumentException If frameRate or compatibility are invalid.
901      */
setFrameRate( @loatRangefrom = 0.0) float frameRate, @FrameRateCompatibility int compatibility)902     public void setFrameRate(
903             @FloatRange(from = 0.0) float frameRate, @FrameRateCompatibility int compatibility) {
904         synchronized (mLock) {
905             checkNotReleasedLocked();
906             int error = nativeSetFrameRate(mNativeObject, frameRate, compatibility);
907             if (error == -EINVAL) {
908                 throw new IllegalArgumentException("Invalid argument to Surface.setFrameRate()");
909             } else if (error != 0) {
910                 throw new RuntimeException("Failed to set frame rate on Surface");
911             }
912         }
913     }
914 
915     /**
916      * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or
917      * when a SurfaceTexture could not successfully be allocated.
918      */
919     @SuppressWarnings("serial")
920     public static class OutOfResourcesException extends RuntimeException {
OutOfResourcesException()921         public OutOfResourcesException() {
922         }
OutOfResourcesException(String name)923         public OutOfResourcesException(String name) {
924             super(name);
925         }
926     }
927 
928     /**
929      * Returns a human readable representation of a rotation.
930      *
931      * @param rotation The rotation.
932      * @return The rotation symbolic name.
933      *
934      * @hide
935      */
rotationToString(int rotation)936     public static String rotationToString(int rotation) {
937         switch (rotation) {
938             case Surface.ROTATION_0: {
939                 return "ROTATION_0";
940             }
941             case Surface.ROTATION_90: {
942                 return "ROTATION_90";
943             }
944             case Surface.ROTATION_180: {
945                 return "ROTATION_180";
946             }
947             case Surface.ROTATION_270: {
948                 return "ROTATION_270";
949             }
950             default: {
951                 return Integer.toString(rotation);
952             }
953         }
954     }
955 
956     /**
957      * A Canvas class that can handle the compatibility mode.
958      * This does two things differently.
959      * <ul>
960      * <li>Returns the width and height of the target metrics, rather than
961      * native. For example, the canvas returns 320x480 even if an app is running
962      * in WVGA high density.
963      * <li>Scales the matrix in setMatrix by the application scale, except if
964      * the matrix looks like obtained from getMatrix. This is a hack to handle
965      * the case that an application uses getMatrix to keep the original matrix,
966      * set matrix of its own, then set the original matrix back. There is no
967      * perfect solution that works for all cases, and there are a lot of cases
968      * that this model does not work, but we hope this works for many apps.
969      * </ul>
970      */
971     private final class CompatibleCanvas extends Canvas {
972         // A temp matrix to remember what an application obtained via {@link getMatrix}
973         private Matrix mOrigMatrix = null;
974 
975         @Override
setMatrix(Matrix matrix)976         public void setMatrix(Matrix matrix) {
977             if (mCompatibleMatrix == null || mOrigMatrix == null || mOrigMatrix.equals(matrix)) {
978                 // don't scale the matrix if it's not compatibility mode, or
979                 // the matrix was obtained from getMatrix.
980                 super.setMatrix(matrix);
981             } else {
982                 Matrix m = new Matrix(mCompatibleMatrix);
983                 m.preConcat(matrix);
984                 super.setMatrix(m);
985             }
986         }
987 
988         @SuppressWarnings("deprecation")
989         @Override
getMatrix(Matrix m)990         public void getMatrix(Matrix m) {
991             super.getMatrix(m);
992             if (mOrigMatrix == null) {
993                 mOrigMatrix = new Matrix();
994             }
995             mOrigMatrix.set(m);
996         }
997     }
998 
999     private final class HwuiContext {
1000         private final RenderNode mRenderNode;
1001         private HardwareRenderer mHardwareRenderer;
1002         private RecordingCanvas mCanvas;
1003         private final boolean mIsWideColorGamut;
1004 
HwuiContext(boolean isWideColorGamut)1005         HwuiContext(boolean isWideColorGamut) {
1006             mRenderNode = RenderNode.create("HwuiCanvas", null);
1007             mRenderNode.setClipToBounds(false);
1008             mRenderNode.setForceDarkAllowed(false);
1009             mIsWideColorGamut = isWideColorGamut;
1010 
1011             mHardwareRenderer = new HardwareRenderer();
1012             mHardwareRenderer.setContentRoot(mRenderNode);
1013             mHardwareRenderer.setSurface(Surface.this, true);
1014             mHardwareRenderer.setWideGamut(isWideColorGamut);
1015             mHardwareRenderer.setLightSourceAlpha(0.0f, 0.0f);
1016             mHardwareRenderer.setLightSourceGeometry(0.0f, 0.0f, 0.0f, 0.0f);
1017         }
1018 
lockCanvas(int width, int height)1019         Canvas lockCanvas(int width, int height) {
1020             if (mCanvas != null) {
1021                 throw new IllegalStateException("Surface was already locked!");
1022             }
1023             mCanvas = mRenderNode.beginRecording(width, height);
1024             return mCanvas;
1025         }
1026 
unlockAndPost(Canvas canvas)1027         void unlockAndPost(Canvas canvas) {
1028             if (canvas != mCanvas) {
1029                 throw new IllegalArgumentException("canvas object must be the same instance that "
1030                         + "was previously returned by lockCanvas");
1031             }
1032             mRenderNode.endRecording();
1033             mCanvas = null;
1034             mHardwareRenderer.createRenderRequest()
1035                     .setVsyncTime(System.nanoTime())
1036                     .syncAndDraw();
1037         }
1038 
updateSurface()1039         void updateSurface() {
1040             mHardwareRenderer.setSurface(Surface.this, true);
1041         }
1042 
destroy()1043         void destroy() {
1044             mHardwareRenderer.destroy();
1045         }
1046 
isWideColorGamut()1047         boolean isWideColorGamut() {
1048             return mIsWideColorGamut;
1049         }
1050     }
1051 }
1052