• 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 #define LOG_TAG "Surface"
18 
19 #include <stdio.h>
20 
21 #include "jni.h"
22 #include "JNIHelp.h"
23 #include "android_os_Parcel.h"
24 #include "android/graphics/GraphicsJNI.h"
25 
26 #include <android_runtime/AndroidRuntime.h>
27 #include <android_runtime/android_view_Surface.h>
28 #include <android_runtime/android_graphics_SurfaceTexture.h>
29 #include <android_runtime/Log.h>
30 
31 #include <binder/Parcel.h>
32 
33 #include <gui/Surface.h>
34 #include <gui/SurfaceControl.h>
35 #include <gui/GLConsumer.h>
36 
37 #include <ui/Rect.h>
38 #include <ui/Region.h>
39 
40 #include <SkCanvas.h>
41 #include <SkBitmap.h>
42 #include <SkImage.h>
43 #include <SkRegion.h>
44 
45 #include <utils/misc.h>
46 #include <utils/Log.h>
47 
48 #include <ScopedUtfChars.h>
49 
50 // ----------------------------------------------------------------------------
51 
52 namespace android {
53 
54 static const char* const OutOfResourcesException =
55     "android/view/Surface$OutOfResourcesException";
56 
57 static struct {
58     jclass clazz;
59     jfieldID mNativeObject;
60     jfieldID mLock;
61     jmethodID ctor;
62 } gSurfaceClassInfo;
63 
64 static struct {
65     jfieldID left;
66     jfieldID top;
67     jfieldID right;
68     jfieldID bottom;
69 } gRectClassInfo;
70 
71 static struct {
72     jfieldID mFinalizer;
73     jfieldID mNativeCanvas;
74     jfieldID mSurfaceFormat;
75 } gCanvasClassInfo;
76 
77 static struct {
78     jfieldID mNativeCanvas;
79 } gCanvasFinalizerClassInfo;
80 
81 // ----------------------------------------------------------------------------
82 
83 // this is just a pointer we use to pass to inc/decStrong
84 static const void *sRefBaseOwner;
85 
android_view_Surface_isInstanceOf(JNIEnv * env,jobject obj)86 bool android_view_Surface_isInstanceOf(JNIEnv* env, jobject obj) {
87     return env->IsInstanceOf(obj, gSurfaceClassInfo.clazz);
88 }
89 
android_view_Surface_getNativeWindow(JNIEnv * env,jobject surfaceObj)90 sp<ANativeWindow> android_view_Surface_getNativeWindow(JNIEnv* env, jobject surfaceObj) {
91     return android_view_Surface_getSurface(env, surfaceObj);
92 }
93 
android_view_Surface_getSurface(JNIEnv * env,jobject surfaceObj)94 sp<Surface> android_view_Surface_getSurface(JNIEnv* env, jobject surfaceObj) {
95     sp<Surface> sur;
96     jobject lock = env->GetObjectField(surfaceObj,
97             gSurfaceClassInfo.mLock);
98     if (env->MonitorEnter(lock) == JNI_OK) {
99         sur = reinterpret_cast<Surface *>(
100                 env->GetIntField(surfaceObj, gSurfaceClassInfo.mNativeObject));
101         env->MonitorExit(lock);
102     }
103     return sur;
104 }
105 
android_view_Surface_createFromIGraphicBufferProducer(JNIEnv * env,const sp<IGraphicBufferProducer> & bufferProducer)106 jobject android_view_Surface_createFromIGraphicBufferProducer(JNIEnv* env,
107         const sp<IGraphicBufferProducer>& bufferProducer) {
108     if (bufferProducer == NULL) {
109         return NULL;
110     }
111 
112     sp<Surface> surface(new Surface(bufferProducer, true));
113     if (surface == NULL) {
114         return NULL;
115     }
116 
117     jobject surfaceObj = env->NewObject(gSurfaceClassInfo.clazz, gSurfaceClassInfo.ctor, surface.get());
118     if (surfaceObj == NULL) {
119         if (env->ExceptionCheck()) {
120             ALOGE("Could not create instance of Surface from IGraphicBufferProducer.");
121             LOGE_EX(env);
122             env->ExceptionClear();
123         }
124         return NULL;
125     }
126     surface->incStrong(&sRefBaseOwner);
127     return surfaceObj;
128 }
129 
130 // ----------------------------------------------------------------------------
131 
isSurfaceValid(const sp<Surface> & sur)132 static inline bool isSurfaceValid(const sp<Surface>& sur) {
133     return Surface::isValid(sur);
134 }
135 
136 // ----------------------------------------------------------------------------
137 
nativeCreateFromSurfaceTexture(JNIEnv * env,jclass clazz,jobject surfaceTextureObj)138 static jint nativeCreateFromSurfaceTexture(JNIEnv* env, jclass clazz,
139         jobject surfaceTextureObj) {
140     sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, surfaceTextureObj));
141     if (producer == NULL) {
142         jniThrowException(env, "java/lang/IllegalArgumentException",
143                 "SurfaceTexture has already been released");
144         return 0;
145     }
146 
147     sp<Surface> surface(new Surface(producer, true));
148     if (surface == NULL) {
149         jniThrowException(env, OutOfResourcesException, NULL);
150         return 0;
151     }
152 
153     surface->incStrong(&sRefBaseOwner);
154     return int(surface.get());
155 }
156 
nativeRelease(JNIEnv * env,jclass clazz,jint nativeObject)157 static void nativeRelease(JNIEnv* env, jclass clazz, jint nativeObject) {
158     sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject));
159     sur->decStrong(&sRefBaseOwner);
160 }
161 
nativeIsValid(JNIEnv * env,jclass clazz,jint nativeObject)162 static jboolean nativeIsValid(JNIEnv* env, jclass clazz, jint nativeObject) {
163     sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject));
164     return isSurfaceValid(sur) ? JNI_TRUE : JNI_FALSE;
165 }
166 
nativeIsConsumerRunningBehind(JNIEnv * env,jclass clazz,jint nativeObject)167 static jboolean nativeIsConsumerRunningBehind(JNIEnv* env, jclass clazz, jint nativeObject) {
168     sp<Surface> sur(reinterpret_cast<Surface *>(nativeObject));
169     if (!isSurfaceValid(sur)) {
170         doThrowIAE(env);
171         return JNI_FALSE;
172     }
173     int value = 0;
174     ANativeWindow* anw = static_cast<ANativeWindow*>(sur.get());
175     anw->query(anw, NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &value);
176     return value;
177 }
178 
convertPixelFormat(PixelFormat format)179 static inline SkBitmap::Config convertPixelFormat(PixelFormat format) {
180     /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then
181         we can map to SkBitmap::kARGB_8888_Config, and optionally call
182         bitmap.setAlphaType(kOpaque_SkAlphaType) on the resulting SkBitmap
183         (as an accelerator)
184     */
185     switch (format) {
186     case PIXEL_FORMAT_RGBX_8888:    return SkBitmap::kARGB_8888_Config;
187     case PIXEL_FORMAT_RGBA_8888:    return SkBitmap::kARGB_8888_Config;
188     case PIXEL_FORMAT_RGB_565:      return SkBitmap::kRGB_565_Config;
189     default:                        return SkBitmap::kNo_Config;
190     }
191 }
192 
swapCanvasPtr(JNIEnv * env,jobject canvasObj,SkCanvas * newCanvas)193 static inline void swapCanvasPtr(JNIEnv* env, jobject canvasObj, SkCanvas* newCanvas) {
194   jobject canvasFinalizerObj = env->GetObjectField(canvasObj, gCanvasClassInfo.mFinalizer);
195   SkCanvas* previousCanvas = reinterpret_cast<SkCanvas*>(
196           env->GetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas));
197   env->SetIntField(canvasObj, gCanvasClassInfo.mNativeCanvas, (int)newCanvas);
198   env->SetIntField(canvasFinalizerObj, gCanvasFinalizerClassInfo.mNativeCanvas, (int)newCanvas);
199   SkSafeUnref(previousCanvas);
200 }
201 
nativeLockCanvas(JNIEnv * env,jclass clazz,jint nativeObject,jobject canvasObj,jobject dirtyRectObj)202 static jint nativeLockCanvas(JNIEnv* env, jclass clazz,
203         jint nativeObject, jobject canvasObj, jobject dirtyRectObj) {
204     sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
205 
206     if (!isSurfaceValid(surface)) {
207         doThrowIAE(env);
208         return 0;
209     }
210 
211     Rect dirtyRect;
212     Rect* dirtyRectPtr = NULL;
213 
214     if (dirtyRectObj) {
215         dirtyRect.left   = env->GetIntField(dirtyRectObj, gRectClassInfo.left);
216         dirtyRect.top    = env->GetIntField(dirtyRectObj, gRectClassInfo.top);
217         dirtyRect.right  = env->GetIntField(dirtyRectObj, gRectClassInfo.right);
218         dirtyRect.bottom = env->GetIntField(dirtyRectObj, gRectClassInfo.bottom);
219         dirtyRectPtr = &dirtyRect;
220     }
221 
222     ANativeWindow_Buffer outBuffer;
223     status_t err = surface->lock(&outBuffer, dirtyRectPtr);
224     if (err < 0) {
225         const char* const exception = (err == NO_MEMORY) ?
226                 OutOfResourcesException :
227                 "java/lang/IllegalArgumentException";
228         jniThrowException(env, exception, NULL);
229         return 0;
230     }
231 
232     // Associate a SkCanvas object to this surface
233     env->SetIntField(canvasObj, gCanvasClassInfo.mSurfaceFormat, outBuffer.format);
234 
235     SkBitmap bitmap;
236     ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
237     bitmap.setConfig(convertPixelFormat(outBuffer.format), outBuffer.width, outBuffer.height, bpr);
238     if (outBuffer.format == PIXEL_FORMAT_RGBX_8888) {
239         bitmap.setAlphaType(kOpaque_SkAlphaType);
240     }
241     if (outBuffer.width > 0 && outBuffer.height > 0) {
242         bitmap.setPixels(outBuffer.bits);
243     } else {
244         // be safe with an empty bitmap.
245         bitmap.setPixels(NULL);
246     }
247 
248     SkCanvas* nativeCanvas = SkNEW_ARGS(SkCanvas, (bitmap));
249     swapCanvasPtr(env, canvasObj, nativeCanvas);
250 
251     if (dirtyRectPtr) {
252         nativeCanvas->clipRect( SkRect::Make(reinterpret_cast<const SkIRect&>(dirtyRect)) );
253     }
254 
255     if (dirtyRectObj) {
256         env->SetIntField(dirtyRectObj, gRectClassInfo.left,   dirtyRect.left);
257         env->SetIntField(dirtyRectObj, gRectClassInfo.top,    dirtyRect.top);
258         env->SetIntField(dirtyRectObj, gRectClassInfo.right,  dirtyRect.right);
259         env->SetIntField(dirtyRectObj, gRectClassInfo.bottom, dirtyRect.bottom);
260     }
261 
262     // Create another reference to the surface and return it.  This reference
263     // should be passed to nativeUnlockCanvasAndPost in place of mNativeObject,
264     // because the latter could be replaced while the surface is locked.
265     sp<Surface> lockedSurface(surface);
266     lockedSurface->incStrong(&sRefBaseOwner);
267     return (int) lockedSurface.get();
268 }
269 
nativeUnlockCanvasAndPost(JNIEnv * env,jclass clazz,jint nativeObject,jobject canvasObj)270 static void nativeUnlockCanvasAndPost(JNIEnv* env, jclass clazz,
271         jint nativeObject, jobject canvasObj) {
272     sp<Surface> surface(reinterpret_cast<Surface *>(nativeObject));
273     if (!isSurfaceValid(surface)) {
274         return;
275     }
276 
277     // detach the canvas from the surface
278     SkCanvas* nativeCanvas = SkNEW(SkCanvas);
279     swapCanvasPtr(env, canvasObj, nativeCanvas);
280 
281     // unlock surface
282     status_t err = surface->unlockAndPost();
283     if (err < 0) {
284         doThrowIAE(env);
285     }
286 }
287 
288 // ----------------------------------------------------------------------------
289 
nativeCreateFromSurfaceControl(JNIEnv * env,jclass clazz,jint surfaceControlNativeObj)290 static jint nativeCreateFromSurfaceControl(JNIEnv* env, jclass clazz,
291         jint surfaceControlNativeObj) {
292     /*
293      * This is used by the WindowManagerService just after constructing
294      * a Surface and is necessary for returning the Surface reference to
295      * the caller. At this point, we should only have a SurfaceControl.
296      */
297 
298     sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(surfaceControlNativeObj));
299     sp<Surface> surface(ctrl->getSurface());
300     if (surface != NULL) {
301         surface->incStrong(&sRefBaseOwner);
302     }
303     return reinterpret_cast<jint>(surface.get());
304 }
305 
nativeReadFromParcel(JNIEnv * env,jclass clazz,jint nativeObject,jobject parcelObj)306 static jint nativeReadFromParcel(JNIEnv* env, jclass clazz,
307         jint nativeObject, jobject parcelObj) {
308     Parcel* parcel = parcelForJavaObject(env, parcelObj);
309     if (parcel == NULL) {
310         doThrowNPE(env);
311         return 0;
312     }
313 
314     sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
315     sp<IBinder> binder(parcel->readStrongBinder());
316 
317     // update the Surface only if the underlying IGraphicBufferProducer
318     // has changed.
319     if (self != NULL
320             && (self->getIGraphicBufferProducer()->asBinder() == binder)) {
321         // same IGraphicBufferProducer, return ourselves
322         return int(self.get());
323     }
324 
325     sp<Surface> sur;
326     sp<IGraphicBufferProducer> gbp(interface_cast<IGraphicBufferProducer>(binder));
327     if (gbp != NULL) {
328         // we have a new IGraphicBufferProducer, create a new Surface for it
329         sur = new Surface(gbp, true);
330         // and keep a reference before passing to java
331         sur->incStrong(&sRefBaseOwner);
332     }
333 
334     if (self != NULL) {
335         // and loose the java reference to ourselves
336         self->decStrong(&sRefBaseOwner);
337     }
338 
339     return int(sur.get());
340 }
341 
nativeWriteToParcel(JNIEnv * env,jclass clazz,jint nativeObject,jobject parcelObj)342 static void nativeWriteToParcel(JNIEnv* env, jclass clazz,
343         jint nativeObject, jobject parcelObj) {
344     Parcel* parcel = parcelForJavaObject(env, parcelObj);
345     if (parcel == NULL) {
346         doThrowNPE(env);
347         return;
348     }
349     sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
350     parcel->writeStrongBinder( self != 0 ? self->getIGraphicBufferProducer()->asBinder() : NULL);
351 }
352 
353 // ----------------------------------------------------------------------------
354 
355 static JNINativeMethod gSurfaceMethods[] = {
356     {"nativeCreateFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)I",
357             (void*)nativeCreateFromSurfaceTexture },
358     {"nativeRelease", "(I)V",
359             (void*)nativeRelease },
360     {"nativeIsValid", "(I)Z",
361             (void*)nativeIsValid },
362     {"nativeIsConsumerRunningBehind", "(I)Z",
363             (void*)nativeIsConsumerRunningBehind },
364     {"nativeLockCanvas", "(ILandroid/graphics/Canvas;Landroid/graphics/Rect;)I",
365             (void*)nativeLockCanvas },
366     {"nativeUnlockCanvasAndPost", "(ILandroid/graphics/Canvas;)V",
367             (void*)nativeUnlockCanvasAndPost },
368     {"nativeCreateFromSurfaceControl", "(I)I",
369             (void*)nativeCreateFromSurfaceControl },
370     {"nativeReadFromParcel", "(ILandroid/os/Parcel;)I",
371             (void*)nativeReadFromParcel },
372     {"nativeWriteToParcel", "(ILandroid/os/Parcel;)V",
373             (void*)nativeWriteToParcel },
374 };
375 
register_android_view_Surface(JNIEnv * env)376 int register_android_view_Surface(JNIEnv* env)
377 {
378     int err = AndroidRuntime::registerNativeMethods(env, "android/view/Surface",
379             gSurfaceMethods, NELEM(gSurfaceMethods));
380 
381     jclass clazz = env->FindClass("android/view/Surface");
382     gSurfaceClassInfo.clazz = jclass(env->NewGlobalRef(clazz));
383     gSurfaceClassInfo.mNativeObject =
384             env->GetFieldID(gSurfaceClassInfo.clazz, "mNativeObject", "I");
385     gSurfaceClassInfo.mLock =
386             env->GetFieldID(gSurfaceClassInfo.clazz, "mLock", "Ljava/lang/Object;");
387     gSurfaceClassInfo.ctor = env->GetMethodID(gSurfaceClassInfo.clazz, "<init>", "(I)V");
388 
389     clazz = env->FindClass("android/graphics/Canvas");
390     gCanvasClassInfo.mFinalizer = env->GetFieldID(clazz, "mFinalizer", "Landroid/graphics/Canvas$CanvasFinalizer;");
391     gCanvasClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "I");
392     gCanvasClassInfo.mSurfaceFormat = env->GetFieldID(clazz, "mSurfaceFormat", "I");
393 
394     clazz = env->FindClass("android/graphics/Canvas$CanvasFinalizer");
395     gCanvasFinalizerClassInfo.mNativeCanvas = env->GetFieldID(clazz, "mNativeCanvas", "I");
396 
397     clazz = env->FindClass("android/graphics/Rect");
398     gRectClassInfo.left = env->GetFieldID(clazz, "left", "I");
399     gRectClassInfo.top = env->GetFieldID(clazz, "top", "I");
400     gRectClassInfo.right = env->GetFieldID(clazz, "right", "I");
401     gRectClassInfo.bottom = env->GetFieldID(clazz, "bottom", "I");
402 
403     return err;
404 }
405 
406 };
407