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