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