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