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         if (mNativeObject != 0) {
345             nativeDestroy(mNativeObject);
346         }
347         release();
348     }
349 
350     /**
351      * Destroys the HwuiContext without completely
352      * releasing the Surface.
353      * @hide
354      */
hwuiDestroy()355     public void hwuiDestroy() {
356         if (mHwuiContext != null) {
357             mHwuiContext.destroy();
358             mHwuiContext = null;
359         }
360     }
361 
362     /**
363      * Returns true if this object holds a valid surface.
364      *
365      * @return True if it holds a physical surface, so lockCanvas() will succeed.
366      * Otherwise returns false.
367      */
isValid()368     public boolean isValid() {
369         synchronized (mLock) {
370             if (mNativeObject == 0) return false;
371             return nativeIsValid(mNativeObject);
372         }
373     }
374 
375     /**
376      * Gets the generation number of this surface, incremented each time
377      * the native surface contained within this object changes.
378      *
379      * @return The current generation number.
380      * @hide
381      */
getGenerationId()382     public int getGenerationId() {
383         synchronized (mLock) {
384             return mGenerationId;
385         }
386     }
387 
388     /**
389      * Returns the next frame number which will be dequeued for rendering.
390      * Intended for use with SurfaceFlinger's deferred transactions API.
391      *
392      * @hide
393      */
394     @UnsupportedAppUsage
getNextFrameNumber()395     public long getNextFrameNumber() {
396         synchronized (mLock) {
397             checkNotReleasedLocked();
398             return nativeGetNextFrameNumber(mNativeObject);
399         }
400     }
401 
402     /**
403      * Returns true if the consumer of this Surface is running behind the producer.
404      *
405      * @return True if the consumer is more than one buffer ahead of the producer.
406      * @hide
407      */
isConsumerRunningBehind()408     public boolean isConsumerRunningBehind() {
409         synchronized (mLock) {
410             checkNotReleasedLocked();
411             return nativeIsConsumerRunningBehind(mNativeObject);
412         }
413     }
414 
415     /**
416      * Returns the default size of this Surface provided by the consumer of the surface.
417      * Should only be used by the producer of the surface.
418      *
419      * @hide
420      */
421     @NonNull
getDefaultSize()422     public Point getDefaultSize() {
423         synchronized (mLock) {
424             checkNotReleasedLocked();
425             return new Point(nativeGetWidth(mNativeObject), nativeGetHeight(mNativeObject));
426         }
427     }
428 
429     /**
430      * Gets a {@link Canvas} for drawing into this surface.
431      *
432      * After drawing into the provided {@link Canvas}, the caller must
433      * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
434      *
435      * @param inOutDirty A rectangle that represents the dirty region that the caller wants
436      * to redraw.  This function may choose to expand the dirty rectangle if for example
437      * the surface has been resized or if the previous contents of the surface were
438      * not available.  The caller must redraw the entire dirty region as represented
439      * by the contents of the inOutDirty rectangle upon return from this function.
440      * The caller may also pass <code>null</code> instead, in the case where the
441      * entire surface should be redrawn.
442      * @return A canvas for drawing into the surface.
443      *
444      * @throws IllegalArgumentException If the inOutDirty rectangle is not valid.
445      * @throws OutOfResourcesException If the canvas cannot be locked.
446      */
lockCanvas(Rect inOutDirty)447     public Canvas lockCanvas(Rect inOutDirty)
448             throws Surface.OutOfResourcesException, IllegalArgumentException {
449         synchronized (mLock) {
450             checkNotReleasedLocked();
451             if (mLockedObject != 0) {
452                 // Ideally, nativeLockCanvas() would throw in this situation and prevent the
453                 // double-lock, but that won't happen if mNativeObject was updated.  We can't
454                 // abandon the old mLockedObject because it might still be in use, so instead
455                 // we just refuse to re-lock the Surface.
456                 throw new IllegalArgumentException("Surface was already locked");
457             }
458             mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);
459             return mCanvas;
460         }
461     }
462 
463     /**
464      * Posts the new contents of the {@link Canvas} to the surface and
465      * releases the {@link Canvas}.
466      *
467      * @param canvas The canvas previously obtained from {@link #lockCanvas}.
468      */
unlockCanvasAndPost(Canvas canvas)469     public void unlockCanvasAndPost(Canvas canvas) {
470         synchronized (mLock) {
471             checkNotReleasedLocked();
472 
473             if (mHwuiContext != null) {
474                 mHwuiContext.unlockAndPost(canvas);
475             } else {
476                 unlockSwCanvasAndPost(canvas);
477             }
478         }
479     }
480 
unlockSwCanvasAndPost(Canvas canvas)481     private void unlockSwCanvasAndPost(Canvas canvas) {
482         if (canvas != mCanvas) {
483             throw new IllegalArgumentException("canvas object must be the same instance that "
484                     + "was previously returned by lockCanvas");
485         }
486         if (mNativeObject != mLockedObject) {
487             Log.w(TAG, "WARNING: Surface's mNativeObject (0x" +
488                     Long.toHexString(mNativeObject) + ") != mLockedObject (0x" +
489                     Long.toHexString(mLockedObject) +")");
490         }
491         if (mLockedObject == 0) {
492             throw new IllegalStateException("Surface was not locked");
493         }
494         try {
495             nativeUnlockCanvasAndPost(mLockedObject, canvas);
496         } finally {
497             nativeRelease(mLockedObject);
498             mLockedObject = 0;
499         }
500     }
501 
502     /**
503      * Gets a {@link Canvas} for drawing into this surface.
504      *
505      * After drawing into the provided {@link Canvas}, the caller must
506      * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
507      *
508      * Unlike {@link #lockCanvas(Rect)} this will return a hardware-accelerated
509      * canvas. See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported">
510      * unsupported drawing operations</a> for a list of what is and isn't
511      * supported in a hardware-accelerated canvas. It is also required to
512      * fully cover the surface every time {@link #lockHardwareCanvas()} is
513      * called as the buffer is not preserved between frames. Partial updates
514      * are not supported.
515      *
516      * @return A canvas for drawing into the surface.
517      *
518      * @throws IllegalStateException If the canvas cannot be locked.
519      */
lockHardwareCanvas()520     public Canvas lockHardwareCanvas() {
521         synchronized (mLock) {
522             checkNotReleasedLocked();
523             if (mHwuiContext == null) {
524                 mHwuiContext = new HwuiContext(false);
525             }
526             return mHwuiContext.lockCanvas(
527                     nativeGetWidth(mNativeObject),
528                     nativeGetHeight(mNativeObject));
529         }
530     }
531 
532     /**
533      * Gets a {@link Canvas} for drawing into this surface that supports wide color gamut.
534      *
535      * After drawing into the provided {@link Canvas}, the caller must
536      * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
537      *
538      * Unlike {@link #lockCanvas(Rect)} and {@link #lockHardwareCanvas()},
539      * this will return a hardware-accelerated canvas that supports wide color gamut.
540      * See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported">
541      * unsupported drawing operations</a> for a list of what is and isn't
542      * supported in a hardware-accelerated canvas. It is also required to
543      * fully cover the surface every time {@link #lockHardwareCanvas()} is
544      * called as the buffer is not preserved between frames. Partial updates
545      * are not supported.
546      *
547      * @return A canvas for drawing into the surface.
548      *
549      * @throws IllegalStateException If the canvas cannot be locked.
550      *
551      * @hide
552      */
lockHardwareWideColorGamutCanvas()553     public Canvas lockHardwareWideColorGamutCanvas() {
554         synchronized (mLock) {
555             checkNotReleasedLocked();
556             if (mHwuiContext != null && !mHwuiContext.isWideColorGamut()) {
557                 mHwuiContext.destroy();
558                 mHwuiContext = null;
559             }
560             if (mHwuiContext == null) {
561                 mHwuiContext = new HwuiContext(true);
562             }
563             return mHwuiContext.lockCanvas(
564                     nativeGetWidth(mNativeObject),
565                     nativeGetHeight(mNativeObject));
566         }
567     }
568 
569     /**
570      * @deprecated This API has been removed and is not supported.  Do not use.
571      */
572     @Deprecated
unlockCanvas(Canvas canvas)573     public void unlockCanvas(Canvas canvas) {
574         throw new UnsupportedOperationException();
575     }
576 
577     /**
578      * Sets the translator used to scale canvas's width/height in compatibility
579      * mode.
580      */
setCompatibilityTranslator(Translator translator)581     void setCompatibilityTranslator(Translator translator) {
582         if (translator != null) {
583             float appScale = translator.applicationScale;
584             mCompatibleMatrix = new Matrix();
585             mCompatibleMatrix.setScale(appScale, appScale);
586         }
587     }
588 
updateNativeObject(long newNativeObject)589     private void updateNativeObject(long newNativeObject) {
590         synchronized (mLock) {
591             if (newNativeObject == mNativeObject) {
592                 return;
593             }
594             if (mNativeObject != 0) {
595                 nativeRelease(mNativeObject);
596             }
597             setNativeObjectLocked(newNativeObject);
598         }
599     }
600 
601     /**
602      * Copy another surface to this one.  This surface now holds a reference
603      * to the same data as the original surface, and is -not- the owner.
604      * This is for use by the window manager when returning a window surface
605      * back from a client, converting it from the representation being managed
606      * by the window manager to the representation the client uses to draw
607      * in to it.
608      *
609      * @param other {@link SurfaceControl} to copy from.
610      * @hide
611      */
612     @UnsupportedAppUsage
copyFrom(SurfaceControl other)613     public void copyFrom(SurfaceControl other) {
614         if (other == null) {
615             throw new IllegalArgumentException("other must not be null");
616         }
617 
618         long surfaceControlPtr = other.mNativeObject;
619         if (surfaceControlPtr == 0) {
620             throw new NullPointerException(
621                     "null SurfaceControl native object. Are you using a released SurfaceControl?");
622         }
623         long newNativeObject = nativeGetFromSurfaceControl(mNativeObject, surfaceControlPtr);
624         updateNativeObject(newNativeObject);
625     }
626 
627     /**
628      * Update the surface if the BLASTBufferQueue IGraphicBufferProducer is different from this
629      * surface's IGraphicBufferProducer.
630      *
631      * @param queue {@link BLASTBufferQueue} to copy from.
632      * @hide
633      */
copyFrom(BLASTBufferQueue queue)634     public void copyFrom(BLASTBufferQueue queue) {
635         if (queue == null) {
636             throw new IllegalArgumentException("queue must not be null");
637         }
638 
639         long blastBufferQueuePtr = queue.mNativeObject;
640         if (blastBufferQueuePtr == 0) {
641             throw new NullPointerException("Null BLASTBufferQueue native object");
642         }
643         long newNativeObject = nativeGetFromBlastBufferQueue(mNativeObject, blastBufferQueuePtr);
644         updateNativeObject(newNativeObject);
645     }
646 
647     /**
648      * Gets a reference a surface created from this one.  This surface now holds a reference
649      * to the same data as the original surface, and is -not- the owner.
650      * This is for use by the window manager when returning a window surface
651      * back from a client, converting it from the representation being managed
652      * by the window manager to the representation the client uses to draw
653      * in to it.
654      *
655      * @param other {@link SurfaceControl} to create surface from.
656      *
657      * @hide
658      */
createFrom(SurfaceControl other)659     public void createFrom(SurfaceControl other) {
660         if (other == null) {
661             throw new IllegalArgumentException("other must not be null");
662         }
663 
664         long surfaceControlPtr = other.mNativeObject;
665         if (surfaceControlPtr == 0) {
666             throw new NullPointerException(
667                     "null SurfaceControl native object. Are you using a released SurfaceControl?");
668         }
669         long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);
670 
671         synchronized (mLock) {
672             if (mNativeObject != 0) {
673                 nativeRelease(mNativeObject);
674             }
675             setNativeObjectLocked(newNativeObject);
676         }
677     }
678 
679     /**
680      * This is intended to be used by {@link SurfaceView#updateWindow} only.
681      * @param other access is not thread safe
682      * @hide
683      * @deprecated
684      */
685     @Deprecated
686     @UnsupportedAppUsage
transferFrom(Surface other)687     public void transferFrom(Surface other) {
688         if (other == null) {
689             throw new IllegalArgumentException("other must not be null");
690         }
691         if (other != this) {
692             final long newPtr;
693             synchronized (other.mLock) {
694                 newPtr = other.mNativeObject;
695                 other.setNativeObjectLocked(0);
696             }
697 
698             synchronized (mLock) {
699                 if (mNativeObject != 0) {
700                     nativeRelease(mNativeObject);
701                 }
702                 setNativeObjectLocked(newPtr);
703             }
704         }
705     }
706 
707     @Override
describeContents()708     public int describeContents() {
709         return 0;
710     }
711 
readFromParcel(Parcel source)712     public void readFromParcel(Parcel source) {
713         if (source == null) {
714             throw new IllegalArgumentException("source must not be null");
715         }
716 
717         synchronized (mLock) {
718             // nativeReadFromParcel() will either return mNativeObject, or
719             // create a new native Surface and return it after reducing
720             // the reference count on mNativeObject.  Either way, it is
721             // not necessary to call nativeRelease() here.
722             // NOTE: This must be kept synchronized with the native parceling code
723             // in frameworks/native/libs/Surface.cpp
724             mName = source.readString();
725             mIsSingleBuffered = source.readInt() != 0;
726             setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
727         }
728     }
729 
730     @Override
writeToParcel(Parcel dest, int flags)731     public void writeToParcel(Parcel dest, int flags) {
732         if (dest == null) {
733             throw new IllegalArgumentException("dest must not be null");
734         }
735         synchronized (mLock) {
736             // NOTE: This must be kept synchronized with the native parceling code
737             // in frameworks/native/libs/Surface.cpp
738             dest.writeString(mName);
739             dest.writeInt(mIsSingleBuffered ? 1 : 0);
740             nativeWriteToParcel(mNativeObject, dest);
741         }
742         if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
743             release();
744         }
745     }
746 
747     @Override
toString()748     public String toString() {
749         synchronized (mLock) {
750             return "Surface(name=" + mName + ")/@0x" +
751                     Integer.toHexString(System.identityHashCode(this));
752         }
753     }
754 
setNativeObjectLocked(long ptr)755     private void setNativeObjectLocked(long ptr) {
756         if (mNativeObject != ptr) {
757             if (mNativeObject == 0 && ptr != 0) {
758                 mCloseGuard.open("release");
759             } else if (mNativeObject != 0 && ptr == 0) {
760                 mCloseGuard.close();
761             }
762             mNativeObject = ptr;
763             mGenerationId += 1;
764             if (mHwuiContext != null) {
765                 mHwuiContext.updateSurface();
766             }
767         }
768     }
769 
checkNotReleasedLocked()770     private void checkNotReleasedLocked() {
771         if (mNativeObject == 0) {
772             throw new IllegalStateException("Surface has already been released.");
773         }
774     }
775 
776     /**
777      * Allocate buffers ahead of time to avoid allocation delays during rendering
778      * @hide
779      */
allocateBuffers()780     public void allocateBuffers() {
781         synchronized (mLock) {
782             checkNotReleasedLocked();
783             nativeAllocateBuffers(mNativeObject);
784         }
785     }
786 
787     /**
788      * Set the scaling mode to be used for this surfaces buffers
789      * @hide
790      */
setScalingMode(@calingMode int scalingMode)791      public void setScalingMode(@ScalingMode int scalingMode) {
792         synchronized (mLock) {
793             checkNotReleasedLocked();
794             int err = nativeSetScalingMode(mNativeObject, scalingMode);
795             if (err != 0) {
796                 throw new IllegalArgumentException("Invalid scaling mode: " + scalingMode);
797             }
798         }
799     }
800 
forceScopedDisconnect()801     void forceScopedDisconnect() {
802         synchronized (mLock) {
803             checkNotReleasedLocked();
804             int err = nativeForceScopedDisconnect(mNativeObject);
805             if (err != 0) {
806                 throw new RuntimeException("Failed to disconnect Surface instance (bad object?)");
807             }
808         }
809     }
810 
811     /**
812      * Transfer ownership of buffer with a color space and present it on the Surface.
813      * The supported color spaces are SRGB and Display P3, other color spaces will be
814      * treated as SRGB.
815      * @hide
816      */
attachAndQueueBufferWithColorSpace(HardwareBuffer buffer, ColorSpace colorSpace)817     public void attachAndQueueBufferWithColorSpace(HardwareBuffer buffer, ColorSpace colorSpace) {
818         synchronized (mLock) {
819             checkNotReleasedLocked();
820             if (colorSpace == null) {
821                 colorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
822             }
823             int err = nativeAttachAndQueueBufferWithColorSpace(mNativeObject, buffer,
824                     colorSpace.getId());
825             if (err != 0) {
826                 throw new RuntimeException(
827                         "Failed to attach and queue buffer to Surface (bad object?), "
828                         + "native error: " + err);
829             }
830         }
831     }
832 
833     /**
834      * Returns whether or not this Surface is backed by a single-buffered SurfaceTexture
835      * @hide
836      */
isSingleBuffered()837     public boolean isSingleBuffered() {
838         return mIsSingleBuffered;
839     }
840 
841     /**
842      * <p>The shared buffer mode allows both the application and the surface compositor
843      * (SurfaceFlinger) to concurrently access this surface's buffer. While the
844      * application is still required to issue a present request
845      * (see {@link #unlockCanvasAndPost(Canvas)}) to the compositor when an update is required,
846      * the compositor may trigger an update at any time. Since the surface's buffer is shared
847      * between the application and the compositor, updates triggered by the compositor may
848      * cause visible tearing.</p>
849      *
850      * <p>The shared buffer mode can be used with
851      * {@link #setAutoRefreshEnabled(boolean) auto-refresh} to avoid the overhead of
852      * issuing present requests.</p>
853      *
854      * <p>If the application uses the shared buffer mode to reduce latency, it is
855      * recommended to use software rendering (see {@link #lockCanvas(Rect)} to ensure
856      * the graphics workloads are not affected by other applications and/or the system
857      * using the GPU. When using software rendering, the application should update the
858      * smallest possible region of the surface required.</p>
859      *
860      * <p class="note">The shared buffer mode might not be supported by the underlying
861      * hardware. Enabling shared buffer mode on hardware that does not support it will
862      * not yield an error but the application will not benefit from lower latency (and
863      * tearing will not be visible).</p>
864      *
865      * <p class="note">Depending on how many and what kind of surfaces are visible, the
866      * surface compositor may need to copy the shared buffer before it is displayed. When
867      * this happens, the latency benefits of shared buffer mode will be reduced.</p>
868      *
869      * @param enabled True to enable the shared buffer mode on this surface, false otherwise
870      *
871      * @see #isSharedBufferModeEnabled()
872      * @see #setAutoRefreshEnabled(boolean)
873      *
874      * @hide
875      */
setSharedBufferModeEnabled(boolean enabled)876     public void setSharedBufferModeEnabled(boolean enabled) {
877         if (mIsSharedBufferModeEnabled != enabled) {
878             int error = nativeSetSharedBufferModeEnabled(mNativeObject, enabled);
879             if (error != 0) {
880                 throw new RuntimeException(
881                         "Failed to set shared buffer mode on Surface (bad object?)");
882             } else {
883                 mIsSharedBufferModeEnabled = enabled;
884             }
885         }
886     }
887 
888     /**
889      * @return True if shared buffer mode is enabled on this surface, false otherwise
890      *
891      * @see #setSharedBufferModeEnabled(boolean)
892      *
893      * @hide
894      */
isSharedBufferModeEnabled()895     public boolean isSharedBufferModeEnabled() {
896         return mIsSharedBufferModeEnabled;
897     }
898 
899     /**
900      * <p>When auto-refresh is enabled, the surface compositor (SurfaceFlinger)
901      * automatically updates the display on a regular refresh cycle. The application
902      * can continue to issue present requests but it is not required. Enabling
903      * auto-refresh may result in visible tearing.</p>
904      *
905      * <p>Auto-refresh has no effect if the {@link #setSharedBufferModeEnabled(boolean)
906      * shared buffer mode} is not enabled.</p>
907      *
908      * <p>Because auto-refresh will trigger continuous updates of the display, it is
909      * recommended to turn it on only when necessary. For example, in a drawing/painting
910      * application auto-refresh should be enabled on finger/pen down and disabled on
911      * finger/pen up.</p>
912      *
913      * @param enabled True to enable auto-refresh on this surface, false otherwise
914      *
915      * @see #isAutoRefreshEnabled()
916      * @see #setSharedBufferModeEnabled(boolean)
917      *
918      * @hide
919      */
setAutoRefreshEnabled(boolean enabled)920     public void setAutoRefreshEnabled(boolean enabled) {
921         if (mIsAutoRefreshEnabled != enabled) {
922             int error = nativeSetAutoRefreshEnabled(mNativeObject, enabled);
923             if (error != 0) {
924                 throw new RuntimeException("Failed to set auto refresh on Surface (bad object?)");
925             } else {
926                 mIsAutoRefreshEnabled = enabled;
927             }
928         }
929     }
930 
931     /**
932      * @return True if auto-refresh is enabled on this surface, false otherwise
933      *
934      * @hide
935      */
isAutoRefreshEnabled()936     public boolean isAutoRefreshEnabled() {
937         return mIsAutoRefreshEnabled;
938     }
939 
940     /**
941      * Sets the intended frame rate for this surface.
942      *
943      * <p>On devices that are capable of running the display at different refresh rates,
944      * the system may choose a display refresh rate to better match this surface's frame
945      * rate. Usage of this API won't introduce frame rate throttling, or affect other
946      * aspects of the application's frame production pipeline. However, because the system
947      * may change the display refresh rate, calls to this function may result in changes
948      * to Choreographer callback timings, and changes to the time interval at which the
949      * system releases buffers back to the application.</p>
950      *
951      * <p>Note that this only has an effect for surfaces presented on the display. If this
952      * surface is consumed by something other than the system compositor, e.g. a media
953      * codec, this call has no effect.</p>
954      *
955      * @param frameRate The intended frame rate of this surface, in frames per second. 0
956      * is a special value that indicates the app will accept the system's choice for the
957      * display frame rate, which is the default behavior if this function isn't
958      * called. The <code>frameRate</code> parameter does <em>not</em> need to be a valid refresh
959      * rate for this device's display - e.g., it's fine to pass 30fps to a device that can only run
960      * the display at 60fps.
961      *
962      * @param compatibility The frame rate compatibility of this surface. The
963      * compatibility value may influence the system's choice of display frame rate.
964      * This parameter is ignored when <code>frameRate</code> is 0.
965      *
966      * @param changeFrameRateStrategy Whether display refresh rate transitions caused by this
967      * surface should be seamless. A seamless transition is one that doesn't have any visual
968      * interruptions, such as a black screen for a second or two. This parameter is ignored when
969      * <code>frameRate</code> is 0.
970      *
971      * @throws IllegalArgumentException If <code>frameRate</code>, <code>compatibility</code> or
972      * <code>changeFrameRateStrategy</code> are invalid.
973      */
setFrameRate(@loatRangefrom = 0.0) float frameRate, @FrameRateCompatibility int compatibility, @ChangeFrameRateStrategy int changeFrameRateStrategy)974     public void setFrameRate(@FloatRange(from = 0.0) float frameRate,
975             @FrameRateCompatibility int compatibility,
976             @ChangeFrameRateStrategy int changeFrameRateStrategy) {
977         synchronized (mLock) {
978             checkNotReleasedLocked();
979             int error = nativeSetFrameRate(mNativeObject, frameRate, compatibility,
980                     changeFrameRateStrategy);
981             if (error == -EINVAL) {
982                 throw new IllegalArgumentException("Invalid argument to Surface.setFrameRate()");
983             } else if (error != 0) {
984                 throw new RuntimeException("Failed to set frame rate on Surface");
985             }
986         }
987     }
988 
989     /**
990      * Sets the intended frame rate for this surface. Any switching of refresh rates is
991      * most probably going to be seamless.
992      *
993      * @see #setFrameRate(float, int, int)
994      */
setFrameRate( @loatRangefrom = 0.0) float frameRate, @FrameRateCompatibility int compatibility)995     public void setFrameRate(
996             @FloatRange(from = 0.0) float frameRate, @FrameRateCompatibility int compatibility) {
997         setFrameRate(frameRate, compatibility, CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
998     }
999 
1000     /**
1001      * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or
1002      * when a SurfaceTexture could not successfully be allocated.
1003      */
1004     @SuppressWarnings("serial")
1005     public static class OutOfResourcesException extends RuntimeException {
OutOfResourcesException()1006         public OutOfResourcesException() {
1007         }
OutOfResourcesException(String name)1008         public OutOfResourcesException(String name) {
1009             super(name);
1010         }
1011     }
1012 
1013     /**
1014      * Returns a human readable representation of a rotation.
1015      *
1016      * @param rotation The rotation.
1017      * @return The rotation symbolic name.
1018      *
1019      * @hide
1020      */
rotationToString(int rotation)1021     public static String rotationToString(int rotation) {
1022         switch (rotation) {
1023             case Surface.ROTATION_0: {
1024                 return "ROTATION_0";
1025             }
1026             case Surface.ROTATION_90: {
1027                 return "ROTATION_90";
1028             }
1029             case Surface.ROTATION_180: {
1030                 return "ROTATION_180";
1031             }
1032             case Surface.ROTATION_270: {
1033                 return "ROTATION_270";
1034             }
1035             default: {
1036                 return Integer.toString(rotation);
1037             }
1038         }
1039     }
1040 
1041     /**
1042      * A Canvas class that can handle the compatibility mode.
1043      * This does two things differently.
1044      * <ul>
1045      * <li>Returns the width and height of the target metrics, rather than
1046      * native. For example, the canvas returns 320x480 even if an app is running
1047      * in WVGA high density.
1048      * <li>Scales the matrix in setMatrix by the application scale, except if
1049      * the matrix looks like obtained from getMatrix. This is a hack to handle
1050      * the case that an application uses getMatrix to keep the original matrix,
1051      * set matrix of its own, then set the original matrix back. There is no
1052      * perfect solution that works for all cases, and there are a lot of cases
1053      * that this model does not work, but we hope this works for many apps.
1054      * </ul>
1055      */
1056     private final class CompatibleCanvas extends Canvas {
1057         // A temp matrix to remember what an application obtained via {@link getMatrix}
1058         private Matrix mOrigMatrix = null;
1059 
1060         @Override
setMatrix(Matrix matrix)1061         public void setMatrix(Matrix matrix) {
1062             if (mCompatibleMatrix == null || mOrigMatrix == null || mOrigMatrix.equals(matrix)) {
1063                 // don't scale the matrix if it's not compatibility mode, or
1064                 // the matrix was obtained from getMatrix.
1065                 super.setMatrix(matrix);
1066             } else {
1067                 Matrix m = new Matrix(mCompatibleMatrix);
1068                 m.preConcat(matrix);
1069                 super.setMatrix(m);
1070             }
1071         }
1072 
1073         @SuppressWarnings("deprecation")
1074         @Override
getMatrix(Matrix m)1075         public void getMatrix(Matrix m) {
1076             super.getMatrix(m);
1077             if (mOrigMatrix == null) {
1078                 mOrigMatrix = new Matrix();
1079             }
1080             mOrigMatrix.set(m);
1081         }
1082     }
1083 
1084     private final class HwuiContext {
1085         private final RenderNode mRenderNode;
1086         private HardwareRenderer mHardwareRenderer;
1087         private RecordingCanvas mCanvas;
1088         private final boolean mIsWideColorGamut;
1089 
HwuiContext(boolean isWideColorGamut)1090         HwuiContext(boolean isWideColorGamut) {
1091             mRenderNode = RenderNode.create("HwuiCanvas", null);
1092             mRenderNode.setClipToBounds(false);
1093             mRenderNode.setForceDarkAllowed(false);
1094             mIsWideColorGamut = isWideColorGamut;
1095 
1096             mHardwareRenderer = new HardwareRenderer();
1097             mHardwareRenderer.setContentRoot(mRenderNode);
1098             mHardwareRenderer.setSurface(Surface.this, true);
1099             mHardwareRenderer.setColorMode(
1100                     isWideColorGamut
1101                             ? ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT
1102                             : ActivityInfo.COLOR_MODE_DEFAULT);
1103             mHardwareRenderer.setLightSourceAlpha(0.0f, 0.0f);
1104             mHardwareRenderer.setLightSourceGeometry(0.0f, 0.0f, 0.0f, 0.0f);
1105         }
1106 
lockCanvas(int width, int height)1107         Canvas lockCanvas(int width, int height) {
1108             if (mCanvas != null) {
1109                 throw new IllegalStateException("Surface was already locked!");
1110             }
1111             mCanvas = mRenderNode.beginRecording(width, height);
1112             return mCanvas;
1113         }
1114 
unlockAndPost(Canvas canvas)1115         void unlockAndPost(Canvas canvas) {
1116             if (canvas != mCanvas) {
1117                 throw new IllegalArgumentException("canvas object must be the same instance that "
1118                         + "was previously returned by lockCanvas");
1119             }
1120             mRenderNode.endRecording();
1121             mCanvas = null;
1122             mHardwareRenderer.createRenderRequest()
1123                     .setVsyncTime(System.nanoTime())
1124                     .syncAndDraw();
1125         }
1126 
updateSurface()1127         void updateSurface() {
1128             mHardwareRenderer.setSurface(Surface.this, true);
1129         }
1130 
destroy()1131         void destroy() {
1132             mHardwareRenderer.destroy();
1133         }
1134 
isWideColorGamut()1135         boolean isWideColorGamut() {
1136             return mIsWideColorGamut;
1137         }
1138     }
1139 }
1140