• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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 "SurfaceControl"
18 
19 #include <stdio.h>
20 
21 #include "jni.h"
22 #include "JNIHelp.h"
23 
24 #include "android_os_Parcel.h"
25 #include "android_util_Binder.h"
26 #include "android/graphics/GraphicsJNI.h"
27 #include "android/graphics/Region.h"
28 
29 #include <android_runtime/AndroidRuntime.h>
30 #include <android_runtime/android_view_Surface.h>
31 #include <android_runtime/android_view_SurfaceSession.h>
32 
33 #include <gui/Surface.h>
34 #include <gui/SurfaceComposerClient.h>
35 
36 #include <ui/DisplayInfo.h>
37 #include <ui/Rect.h>
38 #include <ui/Region.h>
39 
40 #include <utils/Log.h>
41 
42 #include <ScopedUtfChars.h>
43 
44 // ----------------------------------------------------------------------------
45 
46 namespace android {
47 
48 static const char* const OutOfResourcesException =
49     "android/view/Surface$OutOfResourcesException";
50 
51 static struct {
52     jfieldID width;
53     jfieldID height;
54     jfieldID refreshRate;
55     jfieldID density;
56     jfieldID xDpi;
57     jfieldID yDpi;
58     jfieldID secure;
59 } gPhysicalDisplayInfoClassInfo;
60 
61 
62 class ScreenshotPixelRef : public SkPixelRef {
63 public:
ScreenshotPixelRef(SkColorTable * ctable)64     ScreenshotPixelRef(SkColorTable* ctable) {
65         fCTable = ctable;
66         SkSafeRef(ctable);
67         setImmutable();
68     }
69 
~ScreenshotPixelRef()70     virtual ~ScreenshotPixelRef() {
71         SkSafeUnref(fCTable);
72     }
73 
update(const sp<IBinder> & display,int width,int height,int minLayer,int maxLayer,bool allLayers)74     status_t update(const sp<IBinder>& display, int width, int height,
75             int minLayer, int maxLayer, bool allLayers) {
76         status_t res = (width > 0 && height > 0)
77                 ? (allLayers
78                         ? mScreenshot.update(display, width, height)
79                         : mScreenshot.update(display, width, height, minLayer, maxLayer))
80                 : mScreenshot.update(display);
81         if (res != NO_ERROR) {
82             return res;
83         }
84 
85         return NO_ERROR;
86     }
87 
getWidth() const88     uint32_t getWidth() const {
89         return mScreenshot.getWidth();
90     }
91 
getHeight() const92     uint32_t getHeight() const {
93         return mScreenshot.getHeight();
94     }
95 
getStride() const96     uint32_t getStride() const {
97         return mScreenshot.getStride();
98     }
99 
getFormat() const100     uint32_t getFormat() const {
101         return mScreenshot.getFormat();
102     }
103 
104 protected:
105     // overrides from SkPixelRef
onLockPixels(SkColorTable ** ct)106     virtual void* onLockPixels(SkColorTable** ct) {
107         *ct = fCTable;
108         return (void*)mScreenshot.getPixels();
109     }
110 
onUnlockPixels()111     virtual void onUnlockPixels() {
112     }
113 
114     SK_DECLARE_UNFLATTENABLE_OBJECT()
115 private:
116     ScreenshotClient mScreenshot;
117     SkColorTable*    fCTable;
118 
119     typedef SkPixelRef INHERITED;
120 };
121 
122 
123 // ----------------------------------------------------------------------------
124 
nativeCreate(JNIEnv * env,jclass clazz,jobject sessionObj,jstring nameStr,jint w,jint h,jint format,jint flags)125 static jint nativeCreate(JNIEnv* env, jclass clazz, jobject sessionObj,
126         jstring nameStr, jint w, jint h, jint format, jint flags) {
127     ScopedUtfChars name(env, nameStr);
128     sp<SurfaceComposerClient> client(android_view_SurfaceSession_getClient(env, sessionObj));
129     sp<SurfaceControl> surface = client->createSurface(
130             String8(name.c_str()), w, h, format, flags);
131     if (surface == NULL) {
132         jniThrowException(env, OutOfResourcesException, NULL);
133         return 0;
134     }
135     surface->incStrong((void *)nativeCreate);
136     return int(surface.get());
137 }
138 
nativeRelease(JNIEnv * env,jclass clazz,jint nativeObject)139 static void nativeRelease(JNIEnv* env, jclass clazz, jint nativeObject) {
140     sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(nativeObject));
141     ctrl->decStrong((void *)nativeCreate);
142 }
143 
nativeDestroy(JNIEnv * env,jclass clazz,jint nativeObject)144 static void nativeDestroy(JNIEnv* env, jclass clazz, jint nativeObject) {
145     sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(nativeObject));
146     ctrl->clear();
147     ctrl->decStrong((void *)nativeCreate);
148 }
149 
convertPixelFormat(PixelFormat format)150 static inline SkBitmap::Config convertPixelFormat(PixelFormat format) {
151     /* note: if PIXEL_FORMAT_RGBX_8888 means that all alpha bytes are 0xFF, then
152         we can map to SkBitmap::kARGB_8888_Config, and optionally call
153         bitmap.setIsOpaque(true) on the resulting SkBitmap (as an accelerator)
154     */
155     switch (format) {
156     case PIXEL_FORMAT_RGBX_8888:    return SkBitmap::kARGB_8888_Config;
157     case PIXEL_FORMAT_RGBA_8888:    return SkBitmap::kARGB_8888_Config;
158     case PIXEL_FORMAT_RGBA_4444:    return SkBitmap::kARGB_4444_Config;
159     case PIXEL_FORMAT_RGB_565:      return SkBitmap::kRGB_565_Config;
160     case PIXEL_FORMAT_A_8:          return SkBitmap::kA8_Config;
161     default:                        return SkBitmap::kNo_Config;
162     }
163 }
164 
nativeScreenshotBitmap(JNIEnv * env,jclass clazz,jobject displayTokenObj,jint width,jint height,jint minLayer,jint maxLayer,bool allLayers)165 static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, jobject displayTokenObj,
166         jint width, jint height, jint minLayer, jint maxLayer, bool allLayers) {
167     sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
168     if (displayToken == NULL) {
169         return NULL;
170     }
171 
172     ScreenshotPixelRef* pixels = new ScreenshotPixelRef(NULL);
173     if (pixels->update(displayToken, width, height,
174             minLayer, maxLayer, allLayers) != NO_ERROR) {
175         delete pixels;
176         return NULL;
177     }
178 
179     uint32_t w = pixels->getWidth();
180     uint32_t h = pixels->getHeight();
181     uint32_t s = pixels->getStride();
182     uint32_t f = pixels->getFormat();
183     ssize_t bpr = s * android::bytesPerPixel(f);
184 
185     SkBitmap* bitmap = new SkBitmap();
186     bitmap->setConfig(convertPixelFormat(f), w, h, bpr);
187     if (f == PIXEL_FORMAT_RGBX_8888) {
188         bitmap->setIsOpaque(true);
189     }
190 
191     if (w > 0 && h > 0) {
192         bitmap->setPixelRef(pixels)->unref();
193         bitmap->lockPixels();
194     } else {
195         // be safe with an empty bitmap.
196         delete pixels;
197         bitmap->setPixels(NULL);
198     }
199 
200     return GraphicsJNI::createBitmap(env, bitmap, false, NULL);
201 }
202 
nativeScreenshot(JNIEnv * env,jclass clazz,jobject displayTokenObj,jobject surfaceObj,jint width,jint height,jint minLayer,jint maxLayer,bool allLayers)203 static void nativeScreenshot(JNIEnv* env, jclass clazz,
204         jobject displayTokenObj, jobject surfaceObj,
205         jint width, jint height, jint minLayer, jint maxLayer, bool allLayers) {
206     sp<IBinder> displayToken = ibinderForJavaObject(env, displayTokenObj);
207     if (displayToken != NULL) {
208         sp<Surface> consumer = android_view_Surface_getSurface(env, surfaceObj);
209         if (consumer != NULL) {
210             if (allLayers) {
211                 minLayer = 0;
212                 maxLayer = -1;
213             }
214             ScreenshotClient::capture(
215                     displayToken, consumer->getIGraphicBufferProducer(),
216                     width, height, uint32_t(minLayer), uint32_t(maxLayer));
217         }
218     }
219 }
220 
nativeOpenTransaction(JNIEnv * env,jclass clazz)221 static void nativeOpenTransaction(JNIEnv* env, jclass clazz) {
222     SurfaceComposerClient::openGlobalTransaction();
223 }
224 
nativeCloseTransaction(JNIEnv * env,jclass clazz)225 static void nativeCloseTransaction(JNIEnv* env, jclass clazz) {
226     SurfaceComposerClient::closeGlobalTransaction();
227 }
228 
nativeSetAnimationTransaction(JNIEnv * env,jclass clazz)229 static void nativeSetAnimationTransaction(JNIEnv* env, jclass clazz) {
230     SurfaceComposerClient::setAnimationTransaction();
231 }
232 
nativeSetLayer(JNIEnv * env,jclass clazz,jint nativeObject,jint zorder)233 static void nativeSetLayer(JNIEnv* env, jclass clazz, jint nativeObject, jint zorder) {
234     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
235     status_t err = ctrl->setLayer(zorder);
236     if (err < 0 && err != NO_INIT) {
237         doThrowIAE(env);
238     }
239 }
240 
nativeSetPosition(JNIEnv * env,jclass clazz,jint nativeObject,jfloat x,jfloat y)241 static void nativeSetPosition(JNIEnv* env, jclass clazz, jint nativeObject, jfloat x, jfloat y) {
242     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
243     status_t err = ctrl->setPosition(x, y);
244     if (err < 0 && err != NO_INIT) {
245         doThrowIAE(env);
246     }
247 }
248 
nativeSetSize(JNIEnv * env,jclass clazz,jint nativeObject,jint w,jint h)249 static void nativeSetSize(JNIEnv* env, jclass clazz, jint nativeObject, jint w, jint h) {
250     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
251     status_t err = ctrl->setSize(w, h);
252     if (err < 0 && err != NO_INIT) {
253         doThrowIAE(env);
254     }
255 }
256 
nativeSetFlags(JNIEnv * env,jclass clazz,jint nativeObject,jint flags,jint mask)257 static void nativeSetFlags(JNIEnv* env, jclass clazz, jint nativeObject, jint flags, jint mask) {
258     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
259     status_t err = ctrl->setFlags(flags, mask);
260     if (err < 0 && err != NO_INIT) {
261         doThrowIAE(env);
262     }
263 }
264 
nativeSetTransparentRegionHint(JNIEnv * env,jclass clazz,jint nativeObject,jobject regionObj)265 static void nativeSetTransparentRegionHint(JNIEnv* env, jclass clazz, jint nativeObject, jobject regionObj) {
266     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
267     SkRegion* region = android_graphics_Region_getSkRegion(env, regionObj);
268     if (!region) {
269         doThrowIAE(env);
270         return;
271     }
272 
273     const SkIRect& b(region->getBounds());
274     Region reg(Rect(b.fLeft, b.fTop, b.fRight, b.fBottom));
275     if (region->isComplex()) {
276         SkRegion::Iterator it(*region);
277         while (!it.done()) {
278             const SkIRect& r(it.rect());
279             reg.addRectUnchecked(r.fLeft, r.fTop, r.fRight, r.fBottom);
280             it.next();
281         }
282     }
283 
284     status_t err = ctrl->setTransparentRegionHint(reg);
285     if (err < 0 && err != NO_INIT) {
286         doThrowIAE(env);
287     }
288 }
289 
nativeSetAlpha(JNIEnv * env,jclass clazz,jint nativeObject,jfloat alpha)290 static void nativeSetAlpha(JNIEnv* env, jclass clazz, jint nativeObject, jfloat alpha) {
291     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
292     status_t err = ctrl->setAlpha(alpha);
293     if (err < 0 && err != NO_INIT) {
294         doThrowIAE(env);
295     }
296 }
297 
nativeSetMatrix(JNIEnv * env,jclass clazz,jint nativeObject,jfloat dsdx,jfloat dtdx,jfloat dsdy,jfloat dtdy)298 static void nativeSetMatrix(JNIEnv* env, jclass clazz, jint nativeObject,
299         jfloat dsdx, jfloat dtdx, jfloat dsdy, jfloat dtdy) {
300     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
301     status_t err = ctrl->setMatrix(dsdx, dtdx, dsdy, dtdy);
302     if (err < 0 && err != NO_INIT) {
303         doThrowIAE(env);
304     }
305 }
306 
nativeSetWindowCrop(JNIEnv * env,jclass clazz,jint nativeObject,jint l,jint t,jint r,jint b)307 static void nativeSetWindowCrop(JNIEnv* env, jclass clazz, jint nativeObject,
308         jint l, jint t, jint r, jint b) {
309     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
310     Rect crop(l, t, r, b);
311     status_t err = ctrl->setCrop(crop);
312     if (err < 0 && err != NO_INIT) {
313         doThrowIAE(env);
314     }
315 }
316 
nativeSetLayerStack(JNIEnv * env,jclass clazz,jint nativeObject,jint layerStack)317 static void nativeSetLayerStack(JNIEnv* env, jclass clazz, jint nativeObject, jint layerStack) {
318     SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
319     status_t err = ctrl->setLayerStack(layerStack);
320     if (err < 0 && err != NO_INIT) {
321         doThrowIAE(env);
322     }
323 }
324 
nativeGetBuiltInDisplay(JNIEnv * env,jclass clazz,jint id)325 static jobject nativeGetBuiltInDisplay(JNIEnv* env, jclass clazz, jint id) {
326     sp<IBinder> token(SurfaceComposerClient::getBuiltInDisplay(id));
327     return javaObjectForIBinder(env, token);
328 }
329 
nativeCreateDisplay(JNIEnv * env,jclass clazz,jstring nameObj,jboolean secure)330 static jobject nativeCreateDisplay(JNIEnv* env, jclass clazz, jstring nameObj,
331         jboolean secure) {
332     ScopedUtfChars name(env, nameObj);
333     sp<IBinder> token(SurfaceComposerClient::createDisplay(
334             String8(name.c_str()), bool(secure)));
335     return javaObjectForIBinder(env, token);
336 }
337 
nativeSetDisplaySurface(JNIEnv * env,jclass clazz,jobject tokenObj,jint nativeSurfaceObject)338 static void nativeSetDisplaySurface(JNIEnv* env, jclass clazz,
339         jobject tokenObj, jint nativeSurfaceObject) {
340     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
341     if (token == NULL) return;
342     sp<IGraphicBufferProducer> bufferProducer;
343     sp<Surface> sur(reinterpret_cast<Surface *>(nativeSurfaceObject));
344     if (sur != NULL) {
345         bufferProducer = sur->getIGraphicBufferProducer();
346     }
347     SurfaceComposerClient::setDisplaySurface(token, bufferProducer);
348 }
349 
nativeSetDisplayLayerStack(JNIEnv * env,jclass clazz,jobject tokenObj,jint layerStack)350 static void nativeSetDisplayLayerStack(JNIEnv* env, jclass clazz,
351         jobject tokenObj, jint layerStack) {
352     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
353     if (token == NULL) return;
354 
355     SurfaceComposerClient::setDisplayLayerStack(token, layerStack);
356 }
357 
nativeSetDisplayProjection(JNIEnv * env,jclass clazz,jobject tokenObj,jint orientation,jint layerStackRect_left,jint layerStackRect_top,jint layerStackRect_right,jint layerStackRect_bottom,jint displayRect_left,jint displayRect_top,jint displayRect_right,jint displayRect_bottom)358 static void nativeSetDisplayProjection(JNIEnv* env, jclass clazz,
359         jobject tokenObj, jint orientation,
360         jint layerStackRect_left, jint layerStackRect_top, jint layerStackRect_right, jint layerStackRect_bottom,
361         jint displayRect_left, jint displayRect_top, jint displayRect_right, jint displayRect_bottom) {
362     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
363     if (token == NULL) return;
364     Rect layerStackRect(layerStackRect_left, layerStackRect_top, layerStackRect_right, layerStackRect_bottom);
365     Rect displayRect(displayRect_left, displayRect_top, displayRect_right, displayRect_bottom);
366     SurfaceComposerClient::setDisplayProjection(token, orientation, layerStackRect, displayRect);
367 }
368 
nativeGetDisplayInfo(JNIEnv * env,jclass clazz,jobject tokenObj,jobject infoObj)369 static jboolean nativeGetDisplayInfo(JNIEnv* env, jclass clazz,
370         jobject tokenObj, jobject infoObj) {
371     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
372     if (token == NULL) return JNI_FALSE;
373 
374     DisplayInfo info;
375     if (SurfaceComposerClient::getDisplayInfo(token, &info)) {
376         return JNI_FALSE;
377     }
378 
379     env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.width, info.w);
380     env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.height, info.h);
381     env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.refreshRate, info.fps);
382     env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.density, info.density);
383     env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
384     env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
385     env->SetBooleanField(infoObj, gPhysicalDisplayInfoClassInfo.secure, info.secure);
386     return JNI_TRUE;
387 }
388 
nativeBlankDisplay(JNIEnv * env,jclass clazz,jobject tokenObj)389 static void nativeBlankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
390     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
391     if (token == NULL) return;
392 
393     ALOGD_IF_SLOW(100, "Excessive delay in blankDisplay() while turning screen off");
394     SurfaceComposerClient::blankDisplay(token);
395 }
396 
nativeUnblankDisplay(JNIEnv * env,jclass clazz,jobject tokenObj)397 static void nativeUnblankDisplay(JNIEnv* env, jclass clazz, jobject tokenObj) {
398     sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
399     if (token == NULL) return;
400 
401     ALOGD_IF_SLOW(100, "Excessive delay in unblankDisplay() while turning screen on");
402     SurfaceComposerClient::unblankDisplay(token);
403 }
404 
405 // ----------------------------------------------------------------------------
406 
407 static JNINativeMethod sSurfaceControlMethods[] = {
408     {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIII)I",
409             (void*)nativeCreate },
410     {"nativeRelease", "(I)V",
411             (void*)nativeRelease },
412     {"nativeDestroy", "(I)V",
413             (void*)nativeDestroy },
414     {"nativeScreenshot", "(Landroid/os/IBinder;IIIIZ)Landroid/graphics/Bitmap;",
415             (void*)nativeScreenshotBitmap },
416     {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;IIIIZ)V",
417             (void*)nativeScreenshot },
418     {"nativeOpenTransaction", "()V",
419             (void*)nativeOpenTransaction },
420     {"nativeCloseTransaction", "()V",
421             (void*)nativeCloseTransaction },
422     {"nativeSetAnimationTransaction", "()V",
423             (void*)nativeSetAnimationTransaction },
424     {"nativeSetLayer", "(II)V",
425             (void*)nativeSetLayer },
426     {"nativeSetPosition", "(IFF)V",
427             (void*)nativeSetPosition },
428     {"nativeSetSize", "(III)V",
429             (void*)nativeSetSize },
430     {"nativeSetTransparentRegionHint", "(ILandroid/graphics/Region;)V",
431             (void*)nativeSetTransparentRegionHint },
432     {"nativeSetAlpha", "(IF)V",
433             (void*)nativeSetAlpha },
434     {"nativeSetMatrix", "(IFFFF)V",
435             (void*)nativeSetMatrix },
436     {"nativeSetFlags", "(III)V",
437             (void*)nativeSetFlags },
438     {"nativeSetWindowCrop", "(IIIII)V",
439             (void*)nativeSetWindowCrop },
440     {"nativeSetLayerStack", "(II)V",
441             (void*)nativeSetLayerStack },
442     {"nativeGetBuiltInDisplay", "(I)Landroid/os/IBinder;",
443             (void*)nativeGetBuiltInDisplay },
444     {"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;",
445             (void*)nativeCreateDisplay },
446     {"nativeSetDisplaySurface", "(Landroid/os/IBinder;I)V",
447             (void*)nativeSetDisplaySurface },
448     {"nativeSetDisplayLayerStack", "(Landroid/os/IBinder;I)V",
449             (void*)nativeSetDisplayLayerStack },
450     {"nativeSetDisplayProjection", "(Landroid/os/IBinder;IIIIIIIII)V",
451             (void*)nativeSetDisplayProjection },
452     {"nativeGetDisplayInfo", "(Landroid/os/IBinder;Landroid/view/SurfaceControl$PhysicalDisplayInfo;)Z",
453             (void*)nativeGetDisplayInfo },
454     {"nativeBlankDisplay", "(Landroid/os/IBinder;)V",
455             (void*)nativeBlankDisplay },
456     {"nativeUnblankDisplay", "(Landroid/os/IBinder;)V",
457             (void*)nativeUnblankDisplay },
458 };
459 
register_android_view_SurfaceControl(JNIEnv * env)460 int register_android_view_SurfaceControl(JNIEnv* env)
461 {
462     int err = AndroidRuntime::registerNativeMethods(env, "android/view/SurfaceControl",
463             sSurfaceControlMethods, NELEM(sSurfaceControlMethods));
464 
465     jclass clazz = env->FindClass("android/view/SurfaceControl$PhysicalDisplayInfo");
466     gPhysicalDisplayInfoClassInfo.width = env->GetFieldID(clazz, "width", "I");
467     gPhysicalDisplayInfoClassInfo.height = env->GetFieldID(clazz, "height", "I");
468     gPhysicalDisplayInfoClassInfo.refreshRate = env->GetFieldID(clazz, "refreshRate", "F");
469     gPhysicalDisplayInfoClassInfo.density = env->GetFieldID(clazz, "density", "F");
470     gPhysicalDisplayInfoClassInfo.xDpi = env->GetFieldID(clazz, "xDpi", "F");
471     gPhysicalDisplayInfoClassInfo.yDpi = env->GetFieldID(clazz, "yDpi", "F");
472     gPhysicalDisplayInfoClassInfo.secure = env->GetFieldID(clazz, "secure", "Z");
473     return err;
474 }
475 
476 };
477