Graphics.cpp revision f1f48bc7f200f54c76b22d845d8ba8419879b375
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   gLargeBitmap_class;
173static jmethodID gLargeBitmap_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}
380jobject GraphicsJNI::createLargeBitmap(JNIEnv* env, SkLargeBitmap* bitmap)
381{
382    SkASSERT(bitmap != NULL);
383
384    jobject obj = env->AllocObject(gLargeBitmap_class);
385    if (hasException(env)) {
386        obj = NULL;
387        return obj;
388    }
389    if (obj) {
390        env->CallVoidMethod(obj, gLargeBitmap_constructorMethodID, (jint)bitmap);
391        if (hasException(env)) {
392            obj = NULL;
393        }
394    }
395    return obj;
396}
397
398jobject GraphicsJNI::createRegion(JNIEnv* env, SkRegion* region)
399{
400    SkASSERT(region != NULL);
401    jobject obj = env->AllocObject(gRegion_class);
402    if (obj) {
403        env->CallVoidMethod(obj, gRegion_constructorMethodID, (jint)region, 0);
404        if (hasException(env)) {
405            obj = NULL;
406        }
407    }
408    return obj;
409}
410
411#include "SkPixelRef.h"
412
413static JNIEnv* vm2env(JavaVM* vm)
414{
415    JNIEnv* env = NULL;
416    if (vm->GetEnv((void**)&env, JNI_VERSION_1_4) != JNI_OK || NULL == env)
417    {
418        SkDebugf("------- [%p] vm->GetEnv() failed\n", vm);
419        sk_throw();
420    }
421    return env;
422}
423
424#ifdef TRACK_LOCK_COUNT
425    static int gLockCount;
426#endif
427
428///////////////////////////////////////////////////////////////////////////////
429
430#include "SkMallocPixelRef.h"
431
432/*  Extend SkMallocPixelRef to inform the VM when we free up the storage
433*/
434class AndroidPixelRef : public SkMallocPixelRef {
435public:
436    /** Allocate the specified buffer for pixels. The memory is freed when the
437        last owner of this pixelref is gone. Our caller has already informed
438        the VM of our allocation.
439    */
440    AndroidPixelRef(JNIEnv* env, void* storage, size_t size,
441            SkColorTable* ctable) : SkMallocPixelRef(storage, size, ctable) {
442        SkASSERT(storage);
443        SkASSERT(env);
444
445        if (env->GetJavaVM(&fVM) != JNI_OK) {
446            SkDebugf("------ [%p] env->GetJavaVM failed\n", env);
447            sk_throw();
448        }
449    }
450
451    virtual ~AndroidPixelRef() {
452        JNIEnv* env = vm2env(fVM);
453//        SkDebugf("-------------- inform VM we're releasing %d bytes\n", this->getSize());
454        jlong jsize = this->getSize();  // the VM wants longs for the size
455        env->CallVoidMethod(gVMRuntime_singleton,
456                            gVMRuntime_trackExternalFreeMethodID,
457                            jsize);
458        if (GraphicsJNI::hasException(env)) {
459            env->ExceptionClear();
460        }
461    }
462
463private:
464    JavaVM* fVM;
465};
466
467bool GraphicsJNI::setJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
468                                  SkColorTable* ctable, bool reportSizeToVM) {
469    Sk64 size64 = bitmap->getSize64();
470    if (size64.isNeg() || !size64.is32()) {
471        doThrow(env, "java/lang/IllegalArgumentException",
472                     "bitmap size exceeds 32bits");
473        return false;
474    }
475
476    size_t size = size64.get32();
477    jlong jsize = size;  // the VM wants longs for the size
478    if (reportSizeToVM) {
479        //    SkDebugf("-------------- inform VM we've allocated %d bytes\n", size);
480        bool r = env->CallBooleanMethod(gVMRuntime_singleton,
481                                    gVMRuntime_trackExternalAllocationMethodID,
482                                    jsize);
483        if (GraphicsJNI::hasException(env)) {
484            return false;
485        }
486        if (!r) {
487            LOGE("VM won't let us allocate %zd bytes\n", size);
488            doThrowOOME(env, "bitmap size exceeds VM budget");
489            return false;
490        }
491    }
492    // call the version of malloc that returns null on failure
493    void* addr = sk_malloc_flags(size, 0);
494    if (NULL == addr) {
495        if (reportSizeToVM) {
496            //        SkDebugf("-------------- inform VM we're releasing %d bytes which we couldn't allocate\n", size);
497            // we didn't actually allocate it, so inform the VM
498            env->CallVoidMethod(gVMRuntime_singleton,
499                                 gVMRuntime_trackExternalFreeMethodID,
500                                 jsize);
501            if (!GraphicsJNI::hasException(env)) {
502                doThrowOOME(env, "bitmap size too large for malloc");
503            }
504        }
505        return false;
506    }
507
508    SkPixelRef* pr = reportSizeToVM ?
509                        new AndroidPixelRef(env, addr, size, ctable) :
510                        new SkMallocPixelRef(addr, size, ctable);
511    bitmap->setPixelRef(pr)->unref();
512    // since we're already allocated, we lockPixels right away
513    // HeapAllocator behaves this way too
514    bitmap->lockPixels();
515    return true;
516}
517
518///////////////////////////////////////////////////////////////////////////////
519
520JavaPixelAllocator::JavaPixelAllocator(JNIEnv* env, bool reportSizeToVM)
521    : fEnv(env), fReportSizeToVM(reportSizeToVM) {}
522
523bool JavaPixelAllocator::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
524    return GraphicsJNI::setJavaPixelRef(fEnv, bitmap, ctable, fReportSizeToVM);
525}
526
527////////////////////////////////////////////////////////////////////////////////
528
529JavaMemoryUsageReporter::JavaMemoryUsageReporter(JNIEnv* env)
530    : fEnv(env), fTotalSize(0) {}
531
532JavaMemoryUsageReporter::~JavaMemoryUsageReporter() {
533    jlong jtotalSize = fTotalSize;
534    fEnv->CallVoidMethod(gVMRuntime_singleton,
535            gVMRuntime_trackExternalFreeMethodID,
536            jtotalSize);
537}
538
539bool JavaMemoryUsageReporter::reportMemory(size_t memorySize) {
540    jlong jsize = memorySize;  // the VM wants longs for the size
541    bool r = fEnv->CallBooleanMethod(gVMRuntime_singleton,
542            gVMRuntime_trackExternalAllocationMethodID,
543            jsize);
544    if (GraphicsJNI::hasException(fEnv)) {
545        return false;
546    }
547    if (!r) {
548        LOGE("VM won't let us allocate %zd bytes\n", memorySize);
549        doThrowOOME(fEnv, "bitmap size exceeds VM budget");
550        return false;
551    }
552    fTotalSize += memorySize;
553    return true;
554}
555
556////////////////////////////////////////////////////////////////////////////////
557
558static jclass make_globalref(JNIEnv* env, const char classname[])
559{
560    jclass c = env->FindClass(classname);
561    SkASSERT(c);
562    return (jclass)env->NewGlobalRef(c);
563}
564
565static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
566                                const char fieldname[], const char type[])
567{
568    jfieldID id = env->GetFieldID(clazz, fieldname, type);
569    SkASSERT(id);
570    return id;
571}
572
573int register_android_graphics_Graphics(JNIEnv* env)
574{
575    jmethodID m;
576    jclass c;
577
578    gRect_class = make_globalref(env, "android/graphics/Rect");
579    gRect_leftFieldID = getFieldIDCheck(env, gRect_class, "left", "I");
580    gRect_topFieldID = getFieldIDCheck(env, gRect_class, "top", "I");
581    gRect_rightFieldID = getFieldIDCheck(env, gRect_class, "right", "I");
582    gRect_bottomFieldID = getFieldIDCheck(env, gRect_class, "bottom", "I");
583
584    gRectF_class = make_globalref(env, "android/graphics/RectF");
585    gRectF_leftFieldID = getFieldIDCheck(env, gRectF_class, "left", "F");
586    gRectF_topFieldID = getFieldIDCheck(env, gRectF_class, "top", "F");
587    gRectF_rightFieldID = getFieldIDCheck(env, gRectF_class, "right", "F");
588    gRectF_bottomFieldID = getFieldIDCheck(env, gRectF_class, "bottom", "F");
589
590    gPoint_class = make_globalref(env, "android/graphics/Point");
591    gPoint_xFieldID = getFieldIDCheck(env, gPoint_class, "x", "I");
592    gPoint_yFieldID = getFieldIDCheck(env, gPoint_class, "y", "I");
593
594    gPointF_class = make_globalref(env, "android/graphics/PointF");
595    gPointF_xFieldID = getFieldIDCheck(env, gPointF_class, "x", "F");
596    gPointF_yFieldID = getFieldIDCheck(env, gPointF_class, "y", "F");
597
598    gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
599    gBitmap_nativeInstanceID = getFieldIDCheck(env, gBitmap_class, "mNativeBitmap", "I");
600    gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>",
601                                            "(IZ[BI)V");
602
603    gLargeBitmap_class = make_globalref(env, "android/graphics/LargeBitmap");
604    gLargeBitmap_constructorMethodID = env->GetMethodID(gLargeBitmap_class, "<init>", "(I)V");
605
606    gBitmapConfig_class = make_globalref(env, "android/graphics/Bitmap$Config");
607    gBitmapConfig_nativeInstanceID = getFieldIDCheck(env, gBitmapConfig_class,
608                                                     "nativeInt", "I");
609
610    gCanvas_class = make_globalref(env, "android/graphics/Canvas");
611    gCanvas_nativeInstanceID = getFieldIDCheck(env, gCanvas_class, "mNativeCanvas", "I");
612
613    gPaint_class = make_globalref(env, "android/graphics/Paint");
614    gPaint_nativeInstanceID = getFieldIDCheck(env, gPaint_class, "mNativePaint", "I");
615
616    gPicture_class = make_globalref(env, "android/graphics/Picture");
617    gPicture_nativeInstanceID = getFieldIDCheck(env, gPicture_class, "mNativePicture", "I");
618
619    gRegion_class = make_globalref(env, "android/graphics/Region");
620    gRegion_nativeInstanceID = getFieldIDCheck(env, gRegion_class, "mNativeRegion", "I");
621    gRegion_constructorMethodID = env->GetMethodID(gRegion_class, "<init>",
622        "(II)V");
623
624    // Get the VMRuntime class.
625    c = env->FindClass("dalvik/system/VMRuntime");
626    SkASSERT(c);
627    // Look up VMRuntime.getRuntime().
628    m = env->GetStaticMethodID(c, "getRuntime", "()Ldalvik/system/VMRuntime;");
629    SkASSERT(m);
630    // Call VMRuntime.getRuntime() and hold onto its result.
631    gVMRuntime_singleton = env->CallStaticObjectMethod(c, m);
632    SkASSERT(gVMRuntime_singleton);
633    gVMRuntime_singleton = (jobject)env->NewGlobalRef(gVMRuntime_singleton);
634    // Look up the VMRuntime methods we'll be using.
635    gVMRuntime_trackExternalAllocationMethodID =
636                        env->GetMethodID(c, "trackExternalAllocation", "(J)Z");
637    gVMRuntime_trackExternalFreeMethodID =
638                            env->GetMethodID(c, "trackExternalFree", "(J)V");
639
640    NIOBuffer::RegisterJNI(env);
641
642    return 0;
643}
644
645