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