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