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