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