• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.view;
18 
19 import android.annotation.IntDef;
20 import android.content.res.CompatibilityInfo.Translator;
21 import android.graphics.Canvas;
22 import android.graphics.Matrix;
23 import android.graphics.Rect;
24 import android.graphics.SurfaceTexture;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 import android.util.Log;
28 
29 import java.lang.annotation.Retention;
30 import java.lang.annotation.RetentionPolicy;
31 
32 import dalvik.system.CloseGuard;
33 
34 /**
35  * Handle onto a raw buffer that is being managed by the screen compositor.
36  *
37  * <p>A Surface is generally created by or from a consumer of image buffers (such as a
38  * {@link android.graphics.SurfaceTexture}, {@link android.media.MediaRecorder}, or
39  * {@link android.renderscript.Allocation}), and is handed to some kind of producer (such as
40  * {@link android.opengl.EGL14#eglCreateWindowSurface(android.opengl.EGLDisplay,android.opengl.EGLConfig,java.lang.Object,int[],int) OpenGL},
41  * {@link android.media.MediaPlayer#setSurface MediaPlayer}, or
42  * {@link android.hardware.camera2.CameraDevice#createCaptureSession CameraDevice}) to draw
43  * into.</p>
44  *
45  * <p><strong>Note:</strong> A Surface acts like a
46  * {@link java.lang.ref.WeakReference weak reference} to the consumer it is associated with. By
47  * itself it will not keep its parent consumer from being reclaimed.</p>
48  */
49 public class Surface implements Parcelable {
50     private static final String TAG = "Surface";
51 
nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture)52     private static native long nativeCreateFromSurfaceTexture(SurfaceTexture surfaceTexture)
53             throws OutOfResourcesException;
nativeCreateFromSurfaceControl(long surfaceControlNativeObject)54     private static native long nativeCreateFromSurfaceControl(long surfaceControlNativeObject);
55 
nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty)56     private static native long nativeLockCanvas(long nativeObject, Canvas canvas, Rect dirty)
57             throws OutOfResourcesException;
nativeUnlockCanvasAndPost(long nativeObject, Canvas canvas)58     private static native void nativeUnlockCanvasAndPost(long nativeObject, Canvas canvas);
59 
nativeRelease(long nativeObject)60     private static native void nativeRelease(long nativeObject);
nativeIsValid(long nativeObject)61     private static native boolean nativeIsValid(long nativeObject);
nativeIsConsumerRunningBehind(long nativeObject)62     private static native boolean nativeIsConsumerRunningBehind(long nativeObject);
nativeReadFromParcel(long nativeObject, Parcel source)63     private static native long nativeReadFromParcel(long nativeObject, Parcel source);
nativeWriteToParcel(long nativeObject, Parcel dest)64     private static native void nativeWriteToParcel(long nativeObject, Parcel dest);
65 
nativeAllocateBuffers(long nativeObject)66     private static native void nativeAllocateBuffers(long nativeObject);
67 
nativeGetWidth(long nativeObject)68     private static native int nativeGetWidth(long nativeObject);
nativeGetHeight(long nativeObject)69     private static native int nativeGetHeight(long nativeObject);
70 
nativeGetNextFrameNumber(long nativeObject)71     private static native long nativeGetNextFrameNumber(long nativeObject);
nativeSetScalingMode(long nativeObject, int scalingMode)72     private static native int nativeSetScalingMode(long nativeObject, int scalingMode);
nativeSetBuffersTransform(long nativeObject, long transform)73     private static native void nativeSetBuffersTransform(long nativeObject, long transform);
nativeForceScopedDisconnect(long nativeObject)74     private static native int nativeForceScopedDisconnect(long nativeObject);
75 
76     public static final Parcelable.Creator<Surface> CREATOR =
77             new Parcelable.Creator<Surface>() {
78         @Override
79         public Surface createFromParcel(Parcel source) {
80             try {
81                 Surface s = new Surface();
82                 s.readFromParcel(source);
83                 return s;
84             } catch (Exception e) {
85                 Log.e(TAG, "Exception creating surface from parcel", e);
86                 return null;
87             }
88         }
89 
90         @Override
91         public Surface[] newArray(int size) {
92             return new Surface[size];
93         }
94     };
95 
96     private final CloseGuard mCloseGuard = CloseGuard.get();
97 
98     // Guarded state.
99     final Object mLock = new Object(); // protects the native state
100     private String mName;
101     long mNativeObject; // package scope only for SurfaceControl access
102     private long mLockedObject;
103     private int mGenerationId; // incremented each time mNativeObject changes
104     private final Canvas mCanvas = new CompatibleCanvas();
105 
106     // A matrix to scale the matrix set by application. This is set to null for
107     // non compatibility mode.
108     private Matrix mCompatibleMatrix;
109 
110     private HwuiContext mHwuiContext;
111 
112     private boolean mIsSingleBuffered;
113 
114     /** @hide */
115     @Retention(RetentionPolicy.SOURCE)
116     @IntDef({SCALING_MODE_FREEZE, SCALING_MODE_SCALE_TO_WINDOW,
117                     SCALING_MODE_SCALE_CROP, SCALING_MODE_NO_SCALE_CROP})
118     public @interface ScalingMode {}
119     // From system/window.h
120     /** @hide */
121     public static final int SCALING_MODE_FREEZE = 0;
122     /** @hide */
123     public static final int SCALING_MODE_SCALE_TO_WINDOW = 1;
124     /** @hide */
125     public static final int SCALING_MODE_SCALE_CROP = 2;
126     /** @hide */
127     public static final int SCALING_MODE_NO_SCALE_CROP = 3;
128 
129     /** @hide */
130     @IntDef({ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270})
131     @Retention(RetentionPolicy.SOURCE)
132     public @interface Rotation {}
133 
134     /**
135      * Rotation constant: 0 degree rotation (natural orientation)
136      */
137     public static final int ROTATION_0 = 0;
138 
139     /**
140      * Rotation constant: 90 degree rotation.
141      */
142     public static final int ROTATION_90 = 1;
143 
144     /**
145      * Rotation constant: 180 degree rotation.
146      */
147     public static final int ROTATION_180 = 2;
148 
149     /**
150      * Rotation constant: 270 degree rotation.
151      */
152     public static final int ROTATION_270 = 3;
153 
154     /**
155      * Create an empty surface, which will later be filled in by readFromParcel().
156      * @hide
157      */
Surface()158     public Surface() {
159     }
160 
161     /**
162      * Create Surface from a {@link SurfaceTexture}.
163      *
164      * Images drawn to the Surface will be made available to the {@link
165      * SurfaceTexture}, which can attach them to an OpenGL ES texture via {@link
166      * SurfaceTexture#updateTexImage}.
167      *
168      * @param surfaceTexture The {@link SurfaceTexture} that is updated by this
169      * Surface.
170      * @throws OutOfResourcesException if the surface could not be created.
171      */
Surface(SurfaceTexture surfaceTexture)172     public Surface(SurfaceTexture surfaceTexture) {
173         if (surfaceTexture == null) {
174             throw new IllegalArgumentException("surfaceTexture must not be null");
175         }
176         mIsSingleBuffered = surfaceTexture.isSingleBuffered();
177         synchronized (mLock) {
178             mName = surfaceTexture.toString();
179             setNativeObjectLocked(nativeCreateFromSurfaceTexture(surfaceTexture));
180         }
181     }
182 
183     /* called from android_view_Surface_createFromIGraphicBufferProducer() */
Surface(long nativeObject)184     private Surface(long nativeObject) {
185         synchronized (mLock) {
186             setNativeObjectLocked(nativeObject);
187         }
188     }
189 
190     @Override
finalize()191     protected void finalize() throws Throwable {
192         try {
193             if (mCloseGuard != null) {
194                 mCloseGuard.warnIfOpen();
195             }
196             release();
197         } finally {
198             super.finalize();
199         }
200     }
201 
202     /**
203      * Release the local reference to the server-side surface.
204      * Always call release() when you're done with a Surface.
205      * This will make the surface invalid.
206      */
release()207     public void release() {
208         synchronized (mLock) {
209             if (mNativeObject != 0) {
210                 nativeRelease(mNativeObject);
211                 setNativeObjectLocked(0);
212             }
213             if (mHwuiContext != null) {
214                 mHwuiContext.destroy();
215                 mHwuiContext = null;
216             }
217         }
218     }
219 
220     /**
221      * Free all server-side state associated with this surface and
222      * release this object's reference.  This method can only be
223      * called from the process that created the service.
224      * @hide
225      */
destroy()226     public void destroy() {
227         release();
228     }
229 
230     /**
231      * Returns true if this object holds a valid surface.
232      *
233      * @return True if it holds a physical surface, so lockCanvas() will succeed.
234      * Otherwise returns false.
235      */
isValid()236     public boolean isValid() {
237         synchronized (mLock) {
238             if (mNativeObject == 0) return false;
239             return nativeIsValid(mNativeObject);
240         }
241     }
242 
243     /**
244      * Gets the generation number of this surface, incremented each time
245      * the native surface contained within this object changes.
246      *
247      * @return The current generation number.
248      * @hide
249      */
getGenerationId()250     public int getGenerationId() {
251         synchronized (mLock) {
252             return mGenerationId;
253         }
254     }
255 
256     /**
257      * Returns the next frame number which will be dequeued for rendering.
258      * Intended for use with SurfaceFlinger's deferred transactions API.
259      *
260      * @hide
261      */
getNextFrameNumber()262     public long getNextFrameNumber() {
263         synchronized (mLock) {
264             return nativeGetNextFrameNumber(mNativeObject);
265         }
266     }
267 
268     /**
269      * Returns true if the consumer of this Surface is running behind the producer.
270      *
271      * @return True if the consumer is more than one buffer ahead of the producer.
272      * @hide
273      */
isConsumerRunningBehind()274     public boolean isConsumerRunningBehind() {
275         synchronized (mLock) {
276             checkNotReleasedLocked();
277             return nativeIsConsumerRunningBehind(mNativeObject);
278         }
279     }
280 
281     /**
282      * Gets a {@link Canvas} for drawing into this surface.
283      *
284      * After drawing into the provided {@link Canvas}, the caller must
285      * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
286      *
287      * @param inOutDirty A rectangle that represents the dirty region that the caller wants
288      * to redraw.  This function may choose to expand the dirty rectangle if for example
289      * the surface has been resized or if the previous contents of the surface were
290      * not available.  The caller must redraw the entire dirty region as represented
291      * by the contents of the inOutDirty rectangle upon return from this function.
292      * The caller may also pass <code>null</code> instead, in the case where the
293      * entire surface should be redrawn.
294      * @return A canvas for drawing into the surface.
295      *
296      * @throws IllegalArgumentException If the inOutDirty rectangle is not valid.
297      * @throws OutOfResourcesException If the canvas cannot be locked.
298      */
lockCanvas(Rect inOutDirty)299     public Canvas lockCanvas(Rect inOutDirty)
300             throws Surface.OutOfResourcesException, IllegalArgumentException {
301         synchronized (mLock) {
302             checkNotReleasedLocked();
303             if (mLockedObject != 0) {
304                 // Ideally, nativeLockCanvas() would throw in this situation and prevent the
305                 // double-lock, but that won't happen if mNativeObject was updated.  We can't
306                 // abandon the old mLockedObject because it might still be in use, so instead
307                 // we just refuse to re-lock the Surface.
308                 throw new IllegalArgumentException("Surface was already locked");
309             }
310             mLockedObject = nativeLockCanvas(mNativeObject, mCanvas, inOutDirty);
311             return mCanvas;
312         }
313     }
314 
315     /**
316      * Posts the new contents of the {@link Canvas} to the surface and
317      * releases the {@link Canvas}.
318      *
319      * @param canvas The canvas previously obtained from {@link #lockCanvas}.
320      */
unlockCanvasAndPost(Canvas canvas)321     public void unlockCanvasAndPost(Canvas canvas) {
322         synchronized (mLock) {
323             checkNotReleasedLocked();
324 
325             if (mHwuiContext != null) {
326                 mHwuiContext.unlockAndPost(canvas);
327             } else {
328                 unlockSwCanvasAndPost(canvas);
329             }
330         }
331     }
332 
unlockSwCanvasAndPost(Canvas canvas)333     private void unlockSwCanvasAndPost(Canvas canvas) {
334         if (canvas != mCanvas) {
335             throw new IllegalArgumentException("canvas object must be the same instance that "
336                     + "was previously returned by lockCanvas");
337         }
338         if (mNativeObject != mLockedObject) {
339             Log.w(TAG, "WARNING: Surface's mNativeObject (0x" +
340                     Long.toHexString(mNativeObject) + ") != mLockedObject (0x" +
341                     Long.toHexString(mLockedObject) +")");
342         }
343         if (mLockedObject == 0) {
344             throw new IllegalStateException("Surface was not locked");
345         }
346         try {
347             nativeUnlockCanvasAndPost(mLockedObject, canvas);
348         } finally {
349             nativeRelease(mLockedObject);
350             mLockedObject = 0;
351         }
352     }
353 
354     /**
355      * Gets a {@link Canvas} for drawing into this surface.
356      *
357      * After drawing into the provided {@link Canvas}, the caller must
358      * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
359      *
360      * Unlike {@link #lockCanvas(Rect)} this will return a hardware-accelerated
361      * canvas. See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported">
362      * unsupported drawing operations</a> for a list of what is and isn't
363      * supported in a hardware-accelerated canvas. It is also required to
364      * fully cover the surface every time {@link #lockHardwareCanvas()} is
365      * called as the buffer is not preserved between frames. Partial updates
366      * are not supported.
367      *
368      * @return A canvas for drawing into the surface.
369      *
370      * @throws IllegalStateException If the canvas cannot be locked.
371      */
lockHardwareCanvas()372     public Canvas lockHardwareCanvas() {
373         synchronized (mLock) {
374             checkNotReleasedLocked();
375             if (mHwuiContext == null) {
376                 mHwuiContext = new HwuiContext();
377             }
378             return mHwuiContext.lockCanvas(
379                     nativeGetWidth(mNativeObject),
380                     nativeGetHeight(mNativeObject));
381         }
382     }
383 
384     /**
385      * @deprecated This API has been removed and is not supported.  Do not use.
386      */
387     @Deprecated
unlockCanvas(Canvas canvas)388     public void unlockCanvas(Canvas canvas) {
389         throw new UnsupportedOperationException();
390     }
391 
392     /**
393      * Sets the translator used to scale canvas's width/height in compatibility
394      * mode.
395      */
setCompatibilityTranslator(Translator translator)396     void setCompatibilityTranslator(Translator translator) {
397         if (translator != null) {
398             float appScale = translator.applicationScale;
399             mCompatibleMatrix = new Matrix();
400             mCompatibleMatrix.setScale(appScale, appScale);
401         }
402     }
403 
404     /**
405      * Copy another surface to this one.  This surface now holds a reference
406      * to the same data as the original surface, and is -not- the owner.
407      * This is for use by the window manager when returning a window surface
408      * back from a client, converting it from the representation being managed
409      * by the window manager to the representation the client uses to draw
410      * in to it.
411      * @hide
412      */
copyFrom(SurfaceControl other)413     public void copyFrom(SurfaceControl other) {
414         if (other == null) {
415             throw new IllegalArgumentException("other must not be null");
416         }
417 
418         long surfaceControlPtr = other.mNativeObject;
419         if (surfaceControlPtr == 0) {
420             throw new NullPointerException(
421                     "SurfaceControl native object is null. Are you using a released SurfaceControl?");
422         }
423         long newNativeObject = nativeCreateFromSurfaceControl(surfaceControlPtr);
424 
425         synchronized (mLock) {
426             if (mNativeObject != 0) {
427                 nativeRelease(mNativeObject);
428             }
429             setNativeObjectLocked(newNativeObject);
430         }
431     }
432 
433     /**
434      * This is intended to be used by {@link SurfaceView#updateWindow} only.
435      * @param other access is not thread safe
436      * @hide
437      * @deprecated
438      */
439     @Deprecated
transferFrom(Surface other)440     public void transferFrom(Surface other) {
441         if (other == null) {
442             throw new IllegalArgumentException("other must not be null");
443         }
444         if (other != this) {
445             final long newPtr;
446             synchronized (other.mLock) {
447                 newPtr = other.mNativeObject;
448                 other.setNativeObjectLocked(0);
449             }
450 
451             synchronized (mLock) {
452                 if (mNativeObject != 0) {
453                     nativeRelease(mNativeObject);
454                 }
455                 setNativeObjectLocked(newPtr);
456             }
457         }
458     }
459 
460     @Override
describeContents()461     public int describeContents() {
462         return 0;
463     }
464 
readFromParcel(Parcel source)465     public void readFromParcel(Parcel source) {
466         if (source == null) {
467             throw new IllegalArgumentException("source must not be null");
468         }
469 
470         synchronized (mLock) {
471             // nativeReadFromParcel() will either return mNativeObject, or
472             // create a new native Surface and return it after reducing
473             // the reference count on mNativeObject.  Either way, it is
474             // not necessary to call nativeRelease() here.
475             // NOTE: This must be kept synchronized with the native parceling code
476             // in frameworks/native/libs/Surface.cpp
477             mName = source.readString();
478             mIsSingleBuffered = source.readInt() != 0;
479             setNativeObjectLocked(nativeReadFromParcel(mNativeObject, source));
480         }
481     }
482 
483     @Override
writeToParcel(Parcel dest, int flags)484     public void writeToParcel(Parcel dest, int flags) {
485         if (dest == null) {
486             throw new IllegalArgumentException("dest must not be null");
487         }
488         synchronized (mLock) {
489             // NOTE: This must be kept synchronized with the native parceling code
490             // in frameworks/native/libs/Surface.cpp
491             dest.writeString(mName);
492             dest.writeInt(mIsSingleBuffered ? 1 : 0);
493             nativeWriteToParcel(mNativeObject, dest);
494         }
495         if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
496             release();
497         }
498     }
499 
500     @Override
toString()501     public String toString() {
502         synchronized (mLock) {
503             return "Surface(name=" + mName + ")/@0x" +
504                     Integer.toHexString(System.identityHashCode(this));
505         }
506     }
507 
setNativeObjectLocked(long ptr)508     private void setNativeObjectLocked(long ptr) {
509         if (mNativeObject != ptr) {
510             if (mNativeObject == 0 && ptr != 0) {
511                 mCloseGuard.open("release");
512             } else if (mNativeObject != 0 && ptr == 0) {
513                 mCloseGuard.close();
514             }
515             mNativeObject = ptr;
516             mGenerationId += 1;
517             if (mHwuiContext != null) {
518                 mHwuiContext.updateSurface();
519             }
520         }
521     }
522 
checkNotReleasedLocked()523     private void checkNotReleasedLocked() {
524         if (mNativeObject == 0) {
525             throw new IllegalStateException("Surface has already been released.");
526         }
527     }
528 
529     /**
530      * Allocate buffers ahead of time to avoid allocation delays during rendering
531      * @hide
532      */
allocateBuffers()533     public void allocateBuffers() {
534         synchronized (mLock) {
535             checkNotReleasedLocked();
536             nativeAllocateBuffers(mNativeObject);
537         }
538     }
539 
540     /**
541      * Set the scaling mode to be used for this surfaces buffers
542      * @hide
543      */
setScalingMode(@calingMode int scalingMode)544     void setScalingMode(@ScalingMode int scalingMode) {
545         synchronized (mLock) {
546             checkNotReleasedLocked();
547             int err = nativeSetScalingMode(mNativeObject, scalingMode);
548             if (err != 0) {
549                 throw new IllegalArgumentException("Invalid scaling mode: " + scalingMode);
550             }
551         }
552     }
553 
forceScopedDisconnect()554     void forceScopedDisconnect() {
555         synchronized (mLock) {
556             checkNotReleasedLocked();
557             int err = nativeForceScopedDisconnect(mNativeObject);
558             if (err != 0) {
559                 throw new RuntimeException("Failed to disconnect Surface instance (bad object?)");
560             }
561         }
562     }
563 
564     /**
565      * Returns whether or not this Surface is backed by a single-buffered SurfaceTexture
566      * @hide
567      */
isSingleBuffered()568     public boolean isSingleBuffered() {
569         return mIsSingleBuffered;
570     }
571 
572     /**
573      * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or
574      * when a SurfaceTexture could not successfully be allocated.
575      */
576     @SuppressWarnings("serial")
577     public static class OutOfResourcesException extends RuntimeException {
OutOfResourcesException()578         public OutOfResourcesException() {
579         }
OutOfResourcesException(String name)580         public OutOfResourcesException(String name) {
581             super(name);
582         }
583     }
584 
585     /**
586      * Returns a human readable representation of a rotation.
587      *
588      * @param rotation The rotation.
589      * @return The rotation symbolic name.
590      *
591      * @hide
592      */
rotationToString(int rotation)593     public static String rotationToString(int rotation) {
594         switch (rotation) {
595             case Surface.ROTATION_0: {
596                 return "ROTATION_0";
597             }
598             case Surface.ROTATION_90: {
599                 return "ROATATION_90";
600             }
601             case Surface.ROTATION_180: {
602                 return "ROATATION_180";
603             }
604             case Surface.ROTATION_270: {
605                 return "ROATATION_270";
606             }
607             default: {
608                 throw new IllegalArgumentException("Invalid rotation: " + rotation);
609             }
610         }
611     }
612 
613     /**
614      * A Canvas class that can handle the compatibility mode.
615      * This does two things differently.
616      * <ul>
617      * <li>Returns the width and height of the target metrics, rather than
618      * native. For example, the canvas returns 320x480 even if an app is running
619      * in WVGA high density.
620      * <li>Scales the matrix in setMatrix by the application scale, except if
621      * the matrix looks like obtained from getMatrix. This is a hack to handle
622      * the case that an application uses getMatrix to keep the original matrix,
623      * set matrix of its own, then set the original matrix back. There is no
624      * perfect solution that works for all cases, and there are a lot of cases
625      * that this model does not work, but we hope this works for many apps.
626      * </ul>
627      */
628     private final class CompatibleCanvas extends Canvas {
629         // A temp matrix to remember what an application obtained via {@link getMatrix}
630         private Matrix mOrigMatrix = null;
631 
632         @Override
setMatrix(Matrix matrix)633         public void setMatrix(Matrix matrix) {
634             if (mCompatibleMatrix == null || mOrigMatrix == null || mOrigMatrix.equals(matrix)) {
635                 // don't scale the matrix if it's not compatibility mode, or
636                 // the matrix was obtained from getMatrix.
637                 super.setMatrix(matrix);
638             } else {
639                 Matrix m = new Matrix(mCompatibleMatrix);
640                 m.preConcat(matrix);
641                 super.setMatrix(m);
642             }
643         }
644 
645         @SuppressWarnings("deprecation")
646         @Override
getMatrix(Matrix m)647         public void getMatrix(Matrix m) {
648             super.getMatrix(m);
649             if (mOrigMatrix == null) {
650                 mOrigMatrix = new Matrix();
651             }
652             mOrigMatrix.set(m);
653         }
654     }
655 
656     private final class HwuiContext {
657         private final RenderNode mRenderNode;
658         private long mHwuiRenderer;
659         private DisplayListCanvas mCanvas;
660 
HwuiContext()661         HwuiContext() {
662             mRenderNode = RenderNode.create("HwuiCanvas", null);
663             mRenderNode.setClipToBounds(false);
664             mHwuiRenderer = nHwuiCreate(mRenderNode.mNativeRenderNode, mNativeObject);
665         }
666 
lockCanvas(int width, int height)667         Canvas lockCanvas(int width, int height) {
668             if (mCanvas != null) {
669                 throw new IllegalStateException("Surface was already locked!");
670             }
671             mCanvas = mRenderNode.start(width, height);
672             return mCanvas;
673         }
674 
unlockAndPost(Canvas canvas)675         void unlockAndPost(Canvas canvas) {
676             if (canvas != mCanvas) {
677                 throw new IllegalArgumentException("canvas object must be the same instance that "
678                         + "was previously returned by lockCanvas");
679             }
680             mRenderNode.end(mCanvas);
681             mCanvas = null;
682             nHwuiDraw(mHwuiRenderer);
683         }
684 
updateSurface()685         void updateSurface() {
686             nHwuiSetSurface(mHwuiRenderer, mNativeObject);
687         }
688 
destroy()689         void destroy() {
690             if (mHwuiRenderer != 0) {
691                 nHwuiDestroy(mHwuiRenderer);
692                 mHwuiRenderer = 0;
693             }
694         }
695     }
696 
nHwuiCreate(long rootNode, long surface)697     private static native long nHwuiCreate(long rootNode, long surface);
nHwuiSetSurface(long renderer, long surface)698     private static native void nHwuiSetSurface(long renderer, long surface);
nHwuiDraw(long renderer)699     private static native void nHwuiDraw(long renderer);
nHwuiDestroy(long renderer)700     private static native void nHwuiDestroy(long renderer);
701 }
702