Graphics.cpp revision 50ba3d2c09a9131f3578d271adf2bc8258ca1742
1#define LOG_TAG "GraphicsJNI"
2
3#include "jni.h"
4#include "GraphicsJNI.h"
5#include "NIOBuffer.h"
6#include "SkPicture.h"
7#include "SkRegion.h"
8#include <android_runtime/AndroidRuntime.h>
9
10//#define REPORT_SIZE_TO_JVM
11//#define TRACK_LOCK_COUNT
12
13void doThrow(JNIEnv* env, const char* exc, const char* msg) {
14    // don't throw a new exception if we already have one pending
15    if (env->ExceptionCheck() == JNI_FALSE) {
16        jclass npeClazz;
17
18        npeClazz = env->FindClass(exc);
19        LOG_FATAL_IF(npeClazz == NULL, "Unable to find class %s", exc);
20
21        env->ThrowNew(npeClazz, msg);
22    }
23}
24
25void doThrowNPE(JNIEnv* env) {
26    doThrow(env, "java/lang/NullPointerException");
27}
28
29void doThrowAIOOBE(JNIEnv* env) {
30    doThrow(env, "java/lang/ArrayIndexOutOfBoundsException");
31}
32
33void doThrowRE(JNIEnv* env, const char* msg) {
34    doThrow(env, "java/lang/RuntimeException", msg);
35}
36
37void doThrowIAE(JNIEnv* env, const char* msg) {
38    doThrow(env, "java/lang/IllegalArgumentException", msg);
39}
40
41void doThrowISE(JNIEnv* env, const char* msg) {
42    doThrow(env, "java/lang/IllegalStateException", msg);
43}
44
45void doThrowOOME(JNIEnv* env, const char* msg) {
46    doThrow(env, "java/lang/OutOfMemoryError", msg);
47}
48
49void doThrowIOE(JNIEnv* env, const char* msg) {
50    doThrow(env, "java/lang/IOException", msg);
51}
52
53bool GraphicsJNI::hasException(JNIEnv *env) {
54    if (env->ExceptionCheck() != 0) {
55        LOGE("*** Uncaught exception returned from Java call!\n");
56        env->ExceptionDescribe();
57        return true;
58    }
59    return false;
60}
61
62///////////////////////////////////////////////////////////////////////////////
63
64AutoJavaFloatArray::AutoJavaFloatArray(JNIEnv* env, jfloatArray array,
65                                       int minLength, JNIAccess access)
66: fEnv(env), fArray(array), fPtr(NULL), fLen(0) {
67    SkASSERT(env);
68    if (array) {
69        fLen = env->GetArrayLength(array);
70        if (fLen < minLength) {
71            sk_throw();
72        }
73        fPtr = env->GetFloatArrayElements(array, NULL);
74    }
75    fReleaseMode = (access == kRO_JNIAccess) ? JNI_ABORT : 0;
76}
77
78AutoJavaFloatArray::~AutoJavaFloatArray() {
79    if (fPtr) {
80        fEnv->ReleaseFloatArrayElements(fArray, fPtr, fReleaseMode);
81    }
82}
83
84AutoJavaIntArray::AutoJavaIntArray(JNIEnv* env, jintArray array,
85                                       int minLength)
86: fEnv(env), fArray(array), fPtr(NULL), fLen(0) {
87    SkASSERT(env);
88    if (array) {
89        fLen = env->GetArrayLength(array);
90        if (fLen < minLength) {
91            sk_throw();
92        }
93        fPtr = env->GetIntArrayElements(array, NULL);
94    }
95}
96
97AutoJavaIntArray::~AutoJavaIntArray() {
98    if (fPtr) {
99        fEnv->ReleaseIntArrayElements(fArray, fPtr, 0);
100    }
101}
102
103AutoJavaShortArray::AutoJavaShortArray(JNIEnv* env, jshortArray array,
104                                       int minLength, JNIAccess access)
105: fEnv(env), fArray(array), fPtr(NULL), fLen(0) {
106    SkASSERT(env);
107    if (array) {
108        fLen = env->GetArrayLength(array);
109        if (fLen < minLength) {
110            sk_throw();
111        }
112        fPtr = env->GetShortArrayElements(array, NULL);
113    }
114    fReleaseMode = (access == kRO_JNIAccess) ? JNI_ABORT : 0;
115}
116
117AutoJavaShortArray::~AutoJavaShortArray() {
118    if (fPtr) {
119        fEnv->ReleaseShortArrayElements(fArray, fPtr, fReleaseMode);
120    }
121}
122
123AutoJavaByteArray::AutoJavaByteArray(JNIEnv* env, jbyteArray array,
124                                       int minLength)
125: fEnv(env), fArray(array), fPtr(NULL), fLen(0) {
126    SkASSERT(env);
127    if (array) {
128        fLen = env->GetArrayLength(array);
129        if (fLen < minLength) {
130            sk_throw();
131        }
132        fPtr = env->GetByteArrayElements(array, NULL);
133    }
134}
135
136AutoJavaByteArray::~AutoJavaByteArray() {
137    if (fPtr) {
138        fEnv->ReleaseByteArrayElements(fArray, fPtr, 0);
139    }
140}
141
142///////////////////////////////////////////////////////////////////////////////
143
144static jclass   gRect_class;
145static jfieldID gRect_leftFieldID;
146static jfieldID gRect_topFieldID;
147static jfieldID gRect_rightFieldID;
148static jfieldID gRect_bottomFieldID;
149
150static jclass   gRectF_class;
151static jfieldID gRectF_leftFieldID;
152static jfieldID gRectF_topFieldID;
153static jfieldID gRectF_rightFieldID;
154static jfieldID gRectF_bottomFieldID;
155
156static jclass   gPoint_class;
157static jfieldID gPoint_xFieldID;
158static jfieldID gPoint_yFieldID;
159
160static jclass   gPointF_class;
161static jfieldID gPointF_xFieldID;
162static jfieldID gPointF_yFieldID;
163
164static jclass   gBitmap_class;
165static jfieldID gBitmap_nativeInstanceID;
166static jmethodID gBitmap_constructorMethodID;
167static jmethodID gBitmap_allocBufferMethodID;
168
169static jclass   gBitmapConfig_class;
170static jfieldID gBitmapConfig_nativeInstanceID;
171
172static jclass   gBitmapRegionDecoder_class;
173static jmethodID gBitmapRegionDecoder_constructorMethodID;
174
175static jclass   gCanvas_class;
176static jfieldID gCanvas_nativeInstanceID;
177
178static jclass   gPaint_class;
179static jfieldID gPaint_nativeInstanceID;
180
181static jclass   gPicture_class;
182static jfieldID gPicture_nativeInstanceID;
183
184static jclass   gRegion_class;
185static jfieldID gRegion_nativeInstanceID;
186static jmethodID gRegion_constructorMethodID;
187
188static jobject   gVMRuntime_singleton;
189static jmethodID gVMRuntime_trackExternalAllocationMethodID;
190static jmethodID gVMRuntime_trackExternalFreeMethodID;
191
192///////////////////////////////////////////////////////////////////////////////
193
194void GraphicsJNI::get_jrect(JNIEnv* env, jobject obj, int* L, int* T, int* R, int* B)
195{
196    SkASSERT(env->IsInstanceOf(obj, gRect_class));
197
198    *L = env->GetIntField(obj, gRect_leftFieldID);
199    *T = env->GetIntField(obj, gRect_topFieldID);
200    *R = env->GetIntField(obj, gRect_rightFieldID);
201    *B = env->GetIntField(obj, gRect_bottomFieldID);
202}
203
204void GraphicsJNI::set_jrect(JNIEnv* env, jobject obj, int L, int T, int R, int B)
205{
206    SkASSERT(env->IsInstanceOf(obj, gRect_class));
207
208    env->SetIntField(obj, gRect_leftFieldID, L);
209    env->SetIntField(obj, gRect_topFieldID, T);
210    env->SetIntField(obj, gRect_rightFieldID, R);
211    env->SetIntField(obj, gRect_bottomFieldID, B);
212}
213
214SkIRect* GraphicsJNI::jrect_to_irect(JNIEnv* env, jobject obj, SkIRect* ir)
215{
216    SkASSERT(env->IsInstanceOf(obj, gRect_class));
217
218    ir->set(env->GetIntField(obj, gRect_leftFieldID),
219            env->GetIntField(obj, gRect_topFieldID),
220            env->GetIntField(obj, gRect_rightFieldID),
221            env->GetIntField(obj, gRect_bottomFieldID));
222    return ir;
223}
224
225void GraphicsJNI::irect_to_jrect(const SkIRect& ir, JNIEnv* env, jobject obj)
226{
227    SkASSERT(env->IsInstanceOf(obj, gRect_class));
228
229    env->SetIntField(obj, gRect_leftFieldID, ir.fLeft);
230    env->SetIntField(obj, gRect_topFieldID, ir.fTop);
231    env->SetIntField(obj, gRect_rightFieldID, ir.fRight);
232    env->SetIntField(obj, gRect_bottomFieldID, ir.fBottom);
233}
234
235SkRect* GraphicsJNI::jrectf_to_rect(JNIEnv* env, jobject obj, SkRect* r)
236{
237    SkASSERT(env->IsInstanceOf(obj, gRectF_class));
238
239    r->set(SkFloatToScalar(env->GetFloatField(obj, gRectF_leftFieldID)),
240           SkFloatToScalar(env->GetFloatField(obj, gRectF_topFieldID)),
241           SkFloatToScalar(env->GetFloatField(obj, gRectF_rightFieldID)),
242           SkFloatToScalar(env->GetFloatField(obj, gRectF_bottomFieldID)));
243    return r;
244}
245
246SkRect* GraphicsJNI::jrect_to_rect(JNIEnv* env, jobject obj, SkRect* r)
247{
248    SkASSERT(env->IsInstanceOf(obj, gRect_class));
249
250    r->set(SkIntToScalar(env->GetIntField(obj, gRect_leftFieldID)),
251           SkIntToScalar(env->GetIntField(obj, gRect_topFieldID)),
252           SkIntToScalar(env->GetIntField(obj, gRect_rightFieldID)),
253           SkIntToScalar(env->GetIntField(obj, gRect_bottomFieldID)));
254    return r;
255}
256
257void GraphicsJNI::rect_to_jrectf(const SkRect& r, JNIEnv* env, jobject obj)
258{
259    SkASSERT(env->IsInstanceOf(obj, gRectF_class));
260
261    env->SetFloatField(obj, gRectF_leftFieldID, SkScalarToFloat(r.fLeft));
262    env->SetFloatField(obj, gRectF_topFieldID, SkScalarToFloat(r.fTop));
263    env->SetFloatField(obj, gRectF_rightFieldID, SkScalarToFloat(r.fRight));
264    env->SetFloatField(obj, gRectF_bottomFieldID, SkScalarToFloat(r.fBottom));
265}
266
267SkIPoint* GraphicsJNI::jpoint_to_ipoint(JNIEnv* env, jobject obj, SkIPoint* point)
268{
269    SkASSERT(env->IsInstanceOf(obj, gPoint_class));
270
271    point->set(env->GetIntField(obj, gPoint_xFieldID),
272               env->GetIntField(obj, gPoint_yFieldID));
273    return point;
274}
275
276void GraphicsJNI::ipoint_to_jpoint(const SkIPoint& ir, JNIEnv* env, jobject obj)
277{
278    SkASSERT(env->IsInstanceOf(obj, gPoint_class));
279
280    env->SetIntField(obj, gPoint_xFieldID, ir.fX);
281    env->SetIntField(obj, gPoint_yFieldID, ir.fY);
282}
283
284SkPoint* GraphicsJNI::jpointf_to_point(JNIEnv* env, jobject obj, SkPoint* point)
285{
286    SkASSERT(env->IsInstanceOf(obj, gPointF_class));
287
288    point->set(SkFloatToScalar(env->GetIntField(obj, gPointF_xFieldID)),
289               SkFloatToScalar(env->GetIntField(obj, gPointF_yFieldID)));
290    return point;
291}
292
293void GraphicsJNI::point_to_jpointf(const SkPoint& r, JNIEnv* env, jobject obj)
294{
295    SkASSERT(env->IsInstanceOf(obj, gPointF_class));
296
297    env->SetFloatField(obj, gPointF_xFieldID, SkScalarToFloat(r.fX));
298    env->SetFloatField(obj, gPointF_yFieldID, SkScalarToFloat(r.fY));
299}
300
301SkBitmap* GraphicsJNI::getNativeBitmap(JNIEnv* env, jobject bitmap) {
302    SkASSERT(env);
303    SkASSERT(bitmap);
304    SkASSERT(env->IsInstanceOf(bitmap, gBitmap_class));
305    SkBitmap* b = (SkBitmap*)env->GetIntField(bitmap, gBitmap_nativeInstanceID);
306    SkASSERT(b);
307    return b;
308}
309
310SkBitmap::Config GraphicsJNI::getNativeBitmapConfig(JNIEnv* env,
311                                                    jobject jconfig) {
312    SkASSERT(env);
313    if (NULL == jconfig) {
314        return SkBitmap::kNo_Config;
315    }
316    SkASSERT(env->IsInstanceOf(jconfig, gBitmapConfig_class));
317    int c = env->GetIntField(jconfig, gBitmapConfig_nativeInstanceID);
318    if (c < 0 || c >= SkBitmap::kConfigCount) {
319        c = SkBitmap::kNo_Config;
320    }
321    return static_cast<SkBitmap::Config>(c);
322}
323
324SkCanvas* GraphicsJNI::getNativeCanvas(JNIEnv* env, jobject canvas) {
325    SkASSERT(env);
326    SkASSERT(canvas);
327    SkASSERT(env->IsInstanceOf(canvas, gCanvas_class));
328    SkCanvas* c = (SkCanvas*)env->GetIntField(canvas, gCanvas_nativeInstanceID);
329    SkASSERT(c);
330    return c;
331}
332
333SkPaint* GraphicsJNI::getNativePaint(JNIEnv* env, jobject paint) {
334    SkASSERT(env);
335    SkASSERT(paint);
336    SkASSERT(env->IsInstanceOf(paint, gPaint_class));
337    SkPaint* p = (SkPaint*)env->GetIntField(paint, gPaint_nativeInstanceID);
338    SkASSERT(p);
339    return p;
340}
341
342SkPicture* GraphicsJNI::getNativePicture(JNIEnv* env, jobject picture)
343{
344    SkASSERT(env);
345    SkASSERT(picture);
346    SkASSERT(env->IsInstanceOf(picture, gPicture_class));
347    SkPicture* p = (SkPicture*)env->GetIntField(picture, gPicture_nativeInstanceID);
348    SkASSERT(p);
349    return p;
350}
351
352SkRegion* GraphicsJNI::getNativeRegion(JNIEnv* env, jobject region)
353{
354    SkASSERT(env);
355    SkASSERT(region);
356    SkASSERT(env->IsInstanceOf(region, gRegion_class));
357    SkRegion* r = (SkRegion*)env->GetIntField(region, gRegion_nativeInstanceID);
358    SkASSERT(r);
359    return r;
360}
361
362///////////////////////////////////////////////////////////////////////////////////////////
363
364jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, bool isMutable,
365                                  jbyteArray ninepatch, int density)
366{
367    SkASSERT(bitmap != NULL);
368    SkASSERT(NULL != bitmap->pixelRef());
369
370    jobject obj = env->AllocObject(gBitmap_class);
371    if (obj) {
372        env->CallVoidMethod(obj, gBitmap_constructorMethodID,
373                            (jint)bitmap, isMutable, ninepatch, density);
374        if (hasException(env)) {
375            obj = NULL;
376        }
377    }
378    return obj;
379}
380
381jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap)
382{
383    SkASSERT(bitmap != NULL);
384
385    jobject obj = env->AllocObject(gBitmapRegionDecoder_class);
386    if (hasException(env)) {
387        obj = NULL;
388        return obj;
389    }
390    if (obj) {
391        env->CallVoidMethod(obj, gBitmapRegionDecoder_constructorMethodID, (jint)bitmap);
392        if (hasException(env)) {
393            obj = NULL;
394        }
395    }
396    return obj;
397}
398
399jobject GraphicsJNI::createRegion(JNIEnv* env, SkRegion* region)
400{
401    SkASSERT(region != NULL);
402    jobject obj = env->AllocObject(gRegion_class);
403    if (obj) {
404        env->CallVoidMethod(obj, gRegion_constructorMethodID, (jint)region, 0);
405        if (hasException(env)) {
406            obj = NULL;
407        }
408    }
409    return obj;
410}
411
412#include "SkPixelRef.h"
413
414static JNIEnv* vm2env(JavaVM* vm)
415{
416    JNIEnv* env = NULL;
417    if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK || NULL == env)
418    {
419        SkDebugf("------- [%p] vm->GetEnv() failed\n", vm);
420        sk_throw();
421    }
422    return env;
423}
424
425#ifdef TRACK_LOCK_COUNT
426    static int gLockCount;
427#endif
428
429///////////////////////////////////////////////////////////////////////////////
430
431#include "SkMallocPixelRef.h"
432
433/*  Extend SkMallocPixelRef to inform the VM when we free up the storage
434*/
435class AndroidPixelRef : public SkMallocPixelRef {
436public:
437    /** Allocate the specified buffer for pixels. The memory is freed when the
438        last owner of this pixelref is gone. Our caller has already informed
439        the VM of our allocation.
440    */
441    AndroidPixelRef(JNIEnv* env, void* storage, size_t size,
442            SkColorTable* ctable) : SkMallocPixelRef(storage, size, ctable) {
443        SkASSERT(storage);
444        SkASSERT(env);
445
446        if (env->GetJavaVM(&fVM) != JNI_OK) {
447            SkDebugf("------ [%p] env->GetJavaVM failed\n", env);
448            sk_throw();
449        }
450    }
451
452    virtual ~AndroidPixelRef() {
453        JNIEnv* env = vm2env(fVM);
454//        SkDebugf("-------------- inform VM we're releasing %d bytes\n", this->getSize());
455        jlong jsize = this->getSize();  // the VM wants longs for the size
456        env->CallVoidMethod(gVMRuntime_singleton,
457                            gVMRuntime_trackExternalFreeMethodID,
458                            jsize);
459        if (GraphicsJNI::hasException(env)) {
460            env->ExceptionClear();
461        }
462    }
463
464private:
465    JavaVM* fVM;
466};
467
468bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
469                                  SkColorTable* ctable, bool reportSizeToVM) {
470    Sk64 size64 = bitmap->getSize64();
471    if (size64.isNeg() || !size64.is32()) {
472        doThrow(env, "java/lang/IllegalArgumentException",
473                     "bitmap size exceeds 32bits");
474        return false;
475    }
476
477    size_t size = size64.get32();
478    jlong jsize = size;  // the VM wants longs for the size
479    if (reportSizeToVM) {
480        //    SkDebugf("-------------- inform VM we've allocated %d bytes\n", size);
481        bool r = env->CallBooleanMethod(gVMRuntime_singleton,
482                                    gVMRuntime_trackExternalAllocationMethodID,
483                                    jsize);
484        if (GraphicsJNI::hasException(env)) {
485            return false;
486        }
487        if (!r) {
488            LOGE("VM won't let us allocate %zd bytes\n", size);
489            doThrowOOME(env, "bitmap size exceeds VM budget");
490            return false;
491        }
492    }
493    // call the version of malloc that returns null on failure
494    void* addr = sk_malloc_flags(size, 0);
495    if (NULL == addr) {
496        if (reportSizeToVM) {
497            //        SkDebugf("-------------- inform VM we're releasing %d bytes which we couldn't allocate\n", size);
498            // we didn't actually allocate it, so inform the VM
499            env->CallVoidMethod(gVMRuntime_singleton,
500                                 gVMRuntime_trackExternalFreeMethodID,
501                                 jsize);
502            if (!GraphicsJNI::hasException(env)) {
503                doThrowOOME(env, "bitmap size too large for malloc");
504            }
505        }
506        return false;
507    }
508
509    SkPixelRef* pr = reportSizeToVM ?
510                        new AndroidPixelRef(env, addr, size, ctable) :
511                        new SkMallocPixelRef(addr, size, ctable);
512    bitmap->setPixelRef(pr)->unref();
513    // since we're already allocated, we lockPixels right away
514    // HeapAllocator behaves this way too
515    bitmap->lockPixels();
516    return true;
517}
518
519///////////////////////////////////////////////////////////////////////////////
520
521JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env, bool reportSizeToVM)
522    : fReportSizeToVM(reportSizeToVM) {
523    if (env->GetJavaVM(&fVM) != JNI_OK) {
524        SkDebugf("------ [%p] env->GetJavaVM failed\n", env);
525        sk_throw();
526    }
527}
528
529bool JavaPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
530    JNIEnv* env = vm2env(fVM);
531    return GraphicsJNI::setJavaPixelRef(env, bitmap, ctable, fReportSizeToVM);
532}
533
534////////////////////////////////////////////////////////////////////////////////
535
536JavaMemoryUsageReporter::JavaMemoryUsageReporter(JNIEnv* env)
537    : fTotalSize(0) {
538    if (env->GetJavaVM(&fVM) != JNI_OK) {
539        SkDebugf("------ [%p] env->GetJavaVM failed\n", env);
540        sk_throw();
541    }
542}
543
544JavaMemoryUsageReporter::~JavaMemoryUsageReporter() {
545    JNIEnv* env = vm2env(fVM);
546    jlong jtotalSize = fTotalSize;
547    env->CallVoidMethod(gVMRuntime_singleton,
548            gVMRuntime_trackExternalFreeMethodID,
549            jtotalSize);
550}
551
552bool JavaMemoryUsageReporter::reportMemory(size_t memorySize) {
553    jlong jsize = memorySize;  // the VM wants longs for the size
554    JNIEnv* env = vm2env(fVM);
555    bool r = env->CallBooleanMethod(gVMRuntime_singleton,
556            gVMRuntime_trackExternalAllocationMethodID,
557            jsize);
558    if (GraphicsJNI::hasException(env)) {
559        return false;
560    }
561    if (!r) {
562        LOGE("VM won't let us allocate %zd bytes\n", memorySize);
563        doThrowOOME(env, "bitmap size exceeds VM budget");
564        return false;
565    }
566    fTotalSize += memorySize;
567    return true;
568}
569
570////////////////////////////////////////////////////////////////////////////////
571
572static jclass make_globalref(JNIEnv* env, const char classname[])
573{
574    jclass c = env->FindClass(classname);
575    SkASSERT(c);
576    return (jclass)env->NewGlobalRef(c);
577}
578
579static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
580                                const char fieldname[], const char type[])
581{
582    jfieldID id = env->GetFieldID(clazz, fieldname, type);
583    SkASSERT(id);
584    return id;
585}
586
587int register_android_graphics_Graphics(JNIEnv* env)
588{
589    jmethodID m;
590    jclass c;
591
592    gRect_class = make_globalref(env, "android/graphics/Rect");
593    gRect_leftFieldID = getFieldIDCheck(env, gRect_class, "left", "I");
594    gRect_topFieldID = getFieldIDCheck(env, gRect_class, "top", "I");
595    gRect_rightFieldID = getFieldIDCheck(env, gRect_class, "right", "I");
596    gRect_bottomFieldID = getFieldIDCheck(env, gRect_class, "bottom", "I");
597
598    gRectF_class = make_globalref(env, "android/graphics/RectF");
599    gRectF_leftFieldID = getFieldIDCheck(env, gRectF_class, "left", "F");
600    gRectF_topFieldID = getFieldIDCheck(env, gRectF_class, "top", "F");
601    gRectF_rightFieldID = getFieldIDCheck(env, gRectF_class, "right", "F");
602    gRectF_bottomFieldID = getFieldIDCheck(env, gRectF_class, "bottom", "F");
603
604    gPoint_class = make_globalref(env, "android/graphics/Point");
605    gPoint_xFieldID = getFieldIDCheck(env, gPoint_class, "x", "I");
606    gPoint_yFieldID = getFieldIDCheck(env, gPoint_class, "y", "I");
607
608    gPointF_class = make_globalref(env, "android/graphics/PointF");
609    gPointF_xFieldID = getFieldIDCheck(env, gPointF_class, "x", "F");
610    gPointF_yFieldID = getFieldIDCheck(env, gPointF_class, "y", "F");
611
612    gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
613    gBitmap_nativeInstanceID = getFieldIDCheck(env, gBitmap_class, "mNativeBitmap", "I");
614    gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>",
615                                            "(IZ[BI)V");
616
617    gBitmapRegionDecoder_class = make_globalref(env, "android/graphics/BitmapRegionDecoder");
618    gBitmapRegionDecoder_constructorMethodID = env->GetMethodID(gBitmapRegionDecoder_class, "<init>", "(I)V");
619
620    gBitmapConfig_class = make_globalref(env, "android/graphics/Bitmap$Config");
621    gBitmapConfig_nativeInstanceID = getFieldIDCheck(env, gBitmapConfig_class,
622                                                     "nativeInt", "I");
623
624    gCanvas_class = make_globalref(env, "android/graphics/Canvas");
625    gCanvas_nativeInstanceID = getFieldIDCheck(env, gCanvas_class, "mNativeCanvas", "I");
626
627    gPaint_class = make_globalref(env, "android/graphics/Paint");
628    gPaint_nativeInstanceID = getFieldIDCheck(env, gPaint_class, "mNativePaint", "I");
629
630    gPicture_class = make_globalref(env, "android/graphics/Picture");
631    gPicture_nativeInstanceID = getFieldIDCheck(env, gPicture_class, "mNativePicture", "I");
632
633    gRegion_class = make_globalref(env, "android/graphics/Region");
634    gRegion_nativeInstanceID = getFieldIDCheck(env, gRegion_class, "mNativeRegion", "I");
635    gRegion_constructorMethodID = env->GetMethodID(gRegion_class, "<init>",
636        "(II)V");
637
638    // Get the VMRuntime class.
639    c = env->FindClass("dalvik/system/VMRuntime");
640    SkASSERT(c);
641    // Look up VMRuntime.getRuntime().
642    m = env->GetStaticMethodID(c, "getRuntime", "()Ldalvik/system/VMRuntime;");
643    SkASSERT(m);
644    // Call VMRuntime.getRuntime() and hold onto its result.
645    gVMRuntime_singleton = env->CallStaticObjectMethod(c, m);
646    SkASSERT(gVMRuntime_singleton);
647    gVMRuntime_singleton = (jobject)env->NewGlobalRef(gVMRuntime_singleton);
648    // Look up the VMRuntime methods we'll be using.
649    gVMRuntime_trackExternalAllocationMethodID =
650                        env->GetMethodID(c, "trackExternalAllocation", "(J)Z");
651    gVMRuntime_trackExternalFreeMethodID =
652                            env->GetMethodID(c, "trackExternalFree", "(J)V");
653
654    NIOBuffer::RegisterJNI(env);
655
656    return 0;
657}
658