1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 /* 18 * Dalvik implementation of JNI interfaces. 19 */ 20 #include "Dalvik.h" 21 #include "JniInternal.h" 22 #include "ScopedPthreadMutexLock.h" 23 #include "UniquePtr.h" 24 25 #include <stdlib.h> 26 #include <stdarg.h> 27 #include <limits.h> 28 29 /* 30 Native methods and interaction with the GC 31 32 All JNI methods must start by changing their thread status to 33 THREAD_RUNNING, and finish by changing it back to THREAD_NATIVE before 34 returning to native code. The switch to "running" triggers a thread 35 suspension check. 36 37 With a rudimentary GC we should be able to skip the status change for 38 simple functions, e.g. IsSameObject, GetJavaVM, GetStringLength, maybe 39 even access to fields with primitive types. Our options are more limited 40 with a compacting GC. 41 42 For performance reasons we do as little error-checking as possible here. 43 For example, we don't check to make sure the correct type of Object is 44 passed in when setting a field, and we don't prevent you from storing 45 new values in a "final" field. Such things are best handled in the 46 "check" version. For actions that are common, dangerous, and must be 47 checked at runtime, such as array bounds checks, we do the tests here. 48 49 50 General notes on local/global reference tracking 51 52 JNI provides explicit control over natively-held references that the GC 53 needs to know about. These can be local, in which case they're released 54 when the native method returns into the VM, or global, which are held 55 until explicitly released. (There are also weak-global references, 56 which have the lifespan and visibility of global references, but the 57 object they refer to may be collected.) 58 59 The references can be created with explicit JNI NewLocalRef / NewGlobalRef 60 calls. The former is very unusual, the latter is reasonably common 61 (e.g. for caching references to class objects). 62 63 Local references are most often created as a side-effect of JNI functions. 64 For example, the AllocObject/NewObject functions must create local 65 references to the objects returned, because nothing else in the GC root 66 set has a reference to the new objects. 67 68 The most common mode of operation is for a method to create zero or 69 more local references and return. Explicit "local delete" operations 70 are expected to be exceedingly rare, except when walking through an 71 object array, and the Push/PopLocalFrame calls are expected to be used 72 infrequently. For efficient operation, we want to add new local refs 73 with a simple store/increment operation; to avoid infinite growth in 74 pathological situations, we need to reclaim the space used by deleted 75 entries. 76 77 If we just want to maintain a list for the GC root set, we can use an 78 expanding append-only array that compacts when objects are deleted. 79 In typical situations, e.g. running through an array of objects, we will 80 be deleting one of the most recently added entries, so we can minimize 81 the number of elements moved (or avoid having to move any). 82 83 If we want to conceal the pointer values from native code, which is 84 necessary to allow the GC to move JNI-referenced objects around, then we 85 have to use a more complicated indirection mechanism. 86 87 The spec says, "Local references are only valid in the thread in which 88 they are created. The native code must not pass local references from 89 one thread to another." 90 91 92 Pinned objects 93 94 For some large chunks of data, notably primitive arrays and String data, 95 JNI allows the VM to choose whether it wants to pin the array object or 96 make a copy. We currently pin the memory for better execution performance. 97 98 TODO: we're using simple root set references to pin primitive array data, 99 because they have the property we need (i.e. the pointer we return is 100 guaranteed valid until we explicitly release it). However, if we have a 101 compacting GC and don't want to pin all memory held by all global refs, 102 we need to treat these differently. 103 104 105 Global reference tracking 106 107 There should be a small "active" set centered around the most-recently 108 added items. 109 110 Because it's global, access to it has to be synchronized. Additions and 111 removals require grabbing a mutex. If the table serves as an indirection 112 mechanism (i.e. it's not just a list for the benefit of the garbage 113 collector), reference lookups may also require grabbing a mutex. 114 115 The JNI spec does not define any sort of limit, so the list must be able 116 to expand to a reasonable size. It may be useful to log significant 117 increases in usage to help identify resource leaks. 118 119 120 Weak-global reference tracking 121 122 [TBD] 123 124 125 Local reference tracking 126 127 Each Thread/JNIEnv points to an IndirectRefTable. 128 129 We implement Push/PopLocalFrame with actual stack frames. Before a JNI 130 frame gets popped, we set "nextEntry" to the "top" pointer of the current 131 frame, effectively releasing the references. 132 133 The GC will scan all references in the table. 134 135 */ 136 137 #ifdef WITH_JNI_STACK_CHECK 138 # define COMPUTE_STACK_SUM(_self) computeStackSum(_self); 139 # define CHECK_STACK_SUM(_self) checkStackSum(_self); 140 141 /* 142 * Compute a CRC on the entire interpreted stack. 143 * 144 * Would be nice to compute it on "self" as well, but there are parts of 145 * the Thread that can be altered by other threads (e.g. prev/next pointers). 146 */ 147 static void computeStackSum(Thread* self) { 148 const u1* low = (const u1*)SAVEAREA_FROM_FP(self->interpSave.curFrame); 149 u4 crc = dvmInitCrc32(); 150 self->stackCrc = 0; 151 crc = dvmComputeCrc32(crc, low, self->interpStackStart - low); 152 self->stackCrc = crc; 153 } 154 155 /* 156 * Compute a CRC on the entire interpreted stack, and compare it to what 157 * we previously computed. 158 * 159 * We can execute JNI directly from native code without calling in from 160 * interpreted code during VM initialization and immediately after JNI 161 * thread attachment. Another opportunity exists during JNI_OnLoad. Rather 162 * than catching these cases we just ignore them here, which is marginally 163 * less accurate but reduces the amount of code we have to touch with #ifdefs. 164 */ 165 static void checkStackSum(Thread* self) { 166 const u1* low = (const u1*)SAVEAREA_FROM_FP(self->interpSave.curFrame); 167 u4 stackCrc = self->stackCrc; 168 self->stackCrc = 0; 169 u4 crc = dvmInitCrc32(); 170 crc = dvmComputeCrc32(crc, low, self->interpStackStart - low); 171 if (crc != stackCrc) { 172 const Method* meth = dvmGetCurrentJNIMethod(); 173 if (dvmComputeExactFrameDepth(self->interpSave.curFrame) == 1) { 174 LOGD("JNI: bad stack CRC (0x%08x) -- okay during init", stackCrc); 175 } else if (strcmp(meth->name, "nativeLoad") == 0 && 176 (strcmp(meth->clazz->descriptor, "Ljava/lang/Runtime;") == 0)) { 177 LOGD("JNI: bad stack CRC (0x%08x) -- okay during JNI_OnLoad", stackCrc); 178 } else { 179 LOGW("JNI: bad stack CRC (%08x vs %08x)", crc, stackCrc); 180 dvmAbort(); 181 } 182 } 183 self->stackCrc = (u4) -1; /* make logic errors more noticeable */ 184 } 185 186 #else 187 # define COMPUTE_STACK_SUM(_self) ((void)0) 188 # define CHECK_STACK_SUM(_self) ((void)0) 189 #endif 190 191 192 /* 193 * =========================================================================== 194 * Utility functions 195 * =========================================================================== 196 */ 197 198 static inline Thread* self(JNIEnv* env) { 199 Thread* envSelf = ((JNIEnvExt*) env)->self; 200 // When emulating direct pointers with indirect references, it's critical 201 // that we use the correct per-thread indirect reference table. 202 Thread* self = gDvmJni.workAroundAppJniBugs ? dvmThreadSelf() : envSelf; 203 if (self != envSelf) { 204 LOGE("JNI ERROR: env->self != thread-self (%p vs. %p); auto-correcting", 205 envSelf, self); 206 } 207 return self; 208 } 209 210 /* 211 * Entry/exit processing for all JNI calls. 212 * 213 * We skip the (curiously expensive) thread-local storage lookup on our Thread*. 214 * If the caller has passed the wrong JNIEnv in, we're going to be accessing unsynchronized 215 * structures from more than one thread, and things are going to fail 216 * in bizarre ways. This is only sensible if the native code has been 217 * fully exercised with CheckJNI enabled. 218 */ 219 class ScopedJniThreadState { 220 public: 221 explicit ScopedJniThreadState(JNIEnv* env) { 222 mSelf = ::self(env); 223 CHECK_STACK_SUM(mSelf); 224 dvmChangeStatus(mSelf, THREAD_RUNNING); 225 } 226 227 ~ScopedJniThreadState() { 228 dvmChangeStatus(mSelf, THREAD_NATIVE); 229 COMPUTE_STACK_SUM(mSelf); 230 } 231 232 Thread* self() { 233 return mSelf; 234 } 235 236 private: 237 Thread* mSelf; 238 239 // Disallow copy and assignment. 240 ScopedJniThreadState(const ScopedJniThreadState&); 241 void operator=(const ScopedJniThreadState&); 242 }; 243 244 #define kGlobalRefsTableInitialSize 512 245 #define kGlobalRefsTableMaxSize 51200 /* arbitrary, must be < 64K */ 246 #define kGrefWaterInterval 100 247 #define kTrackGrefUsage true 248 249 #define kWeakGlobalRefsTableInitialSize 16 250 251 #define kPinTableInitialSize 16 252 #define kPinTableMaxSize 1024 253 #define kPinComplainThreshold 10 254 255 bool dvmJniStartup() { 256 if (!gDvm.jniGlobalRefTable.init(kGlobalRefsTableInitialSize, 257 kGlobalRefsTableMaxSize, 258 kIndirectKindGlobal)) { 259 return false; 260 } 261 if (!gDvm.jniWeakGlobalRefTable.init(kWeakGlobalRefsTableInitialSize, 262 kGlobalRefsTableMaxSize, 263 kIndirectKindWeakGlobal)) { 264 return false; 265 } 266 267 dvmInitMutex(&gDvm.jniGlobalRefLock); 268 dvmInitMutex(&gDvm.jniWeakGlobalRefLock); 269 gDvm.jniGlobalRefLoMark = 0; 270 gDvm.jniGlobalRefHiMark = kGrefWaterInterval * 2; 271 272 if (!dvmInitReferenceTable(&gDvm.jniPinRefTable, kPinTableInitialSize, kPinTableMaxSize)) { 273 return false; 274 } 275 276 dvmInitMutex(&gDvm.jniPinRefLock); 277 278 return true; 279 } 280 281 void dvmJniShutdown() { 282 gDvm.jniGlobalRefTable.destroy(); 283 gDvm.jniWeakGlobalRefTable.destroy(); 284 dvmClearReferenceTable(&gDvm.jniPinRefTable); 285 } 286 287 /* 288 * Find the JNIEnv associated with the current thread. 289 * 290 * Currently stored in the Thread struct. Could also just drop this into 291 * thread-local storage. 292 */ 293 JNIEnvExt* dvmGetJNIEnvForThread() { 294 Thread* self = dvmThreadSelf(); 295 if (self == NULL) { 296 return NULL; 297 } 298 return (JNIEnvExt*) dvmGetThreadJNIEnv(self); 299 } 300 301 /* 302 * Retrieve the ReferenceTable struct for the current thread. 303 * 304 * Going through "env" rather than dvmThreadSelf() is faster but will 305 * get weird if the JNI code is passing the wrong JNIEnv around. 306 */ 307 static inline IndirectRefTable* getLocalRefTable(JNIEnv* env) { 308 return &self(env)->jniLocalRefTable; 309 } 310 311 /* 312 * Convert an indirect reference to an Object reference. The indirect 313 * reference may be local, global, or weak-global. 314 * 315 * If "jobj" is NULL, or is a weak global reference whose reference has 316 * been cleared, this returns NULL. If jobj is an invalid indirect 317 * reference, kInvalidIndirectRefObject is returned. 318 * 319 * Note "env" may be NULL when decoding global references. 320 */ 321 Object* dvmDecodeIndirectRef(JNIEnv* env, jobject jobj) { 322 if (jobj == NULL) { 323 return NULL; 324 } 325 326 switch (indirectRefKind(jobj)) { 327 case kIndirectKindLocal: 328 { 329 Object* result = getLocalRefTable(env)->get(jobj); 330 if (result == NULL) { 331 LOGE("JNI ERROR (app bug): use of deleted local reference (%p)", jobj); 332 dvmAbort(); 333 } 334 return result; 335 } 336 case kIndirectKindGlobal: 337 { 338 // TODO: find a way to avoid the mutex activity here 339 IndirectRefTable* pRefTable = &gDvm.jniGlobalRefTable; 340 ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock); 341 Object* result = pRefTable->get(jobj); 342 if (result == NULL) { 343 LOGE("JNI ERROR (app bug): use of deleted global reference (%p)", jobj); 344 dvmAbort(); 345 } 346 return result; 347 } 348 case kIndirectKindWeakGlobal: 349 { 350 // TODO: find a way to avoid the mutex activity here 351 IndirectRefTable* pRefTable = &gDvm.jniWeakGlobalRefTable; 352 ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock); 353 Object* result = pRefTable->get(jobj); 354 if (result == kClearedJniWeakGlobal) { 355 result = NULL; 356 } else if (result == NULL) { 357 LOGE("JNI ERROR (app bug): use of deleted weak global reference (%p)", jobj); 358 dvmAbort(); 359 } 360 return result; 361 } 362 case kIndirectKindInvalid: 363 default: 364 if (gDvmJni.workAroundAppJniBugs) { 365 // Assume an invalid local reference is actually a direct pointer. 366 return reinterpret_cast<Object*>(jobj); 367 } 368 LOGW("Invalid indirect reference %p in decodeIndirectRef", jobj); 369 dvmAbort(); 370 return kInvalidIndirectRefObject; 371 } 372 } 373 374 /* 375 * Add a local reference for an object to the current stack frame. When 376 * the native function returns, the reference will be discarded. 377 * 378 * We need to allow the same reference to be added multiple times. 379 * 380 * This will be called on otherwise unreferenced objects. We cannot do 381 * GC allocations here, and it's best if we don't grab a mutex. 382 * 383 * Returns the local reference (currently just the same pointer that was 384 * passed in), or NULL on failure. 385 */ 386 static jobject addLocalReference(JNIEnv* env, Object* obj) { 387 if (obj == NULL) { 388 return NULL; 389 } 390 391 IndirectRefTable* pRefTable = getLocalRefTable(env); 392 void* curFrame = self(env)->interpSave.curFrame; 393 u4 cookie = SAVEAREA_FROM_FP(curFrame)->xtra.localRefCookie; 394 jobject jobj = (jobject) pRefTable->add(cookie, obj); 395 if (jobj == NULL) { 396 pRefTable->dump("JNI local"); 397 LOGE("Failed adding to JNI local ref table (has %zd entries)", 398 pRefTable->capacity()); 399 dvmDumpThread(dvmThreadSelf(), false); 400 dvmAbort(); // spec says call FatalError; this is equivalent 401 } else { 402 if (false) { 403 LOGI("LREF add %p (%s.%s) (ent=%zd)", obj, 404 dvmGetCurrentJNIMethod()->clazz->descriptor, 405 dvmGetCurrentJNIMethod()->name, 406 pRefTable->capacity()); 407 } 408 } 409 410 #if 0 // TODO: fix this to understand PushLocalFrame, so we can turn it on. 411 if (gDvmJni.useCheckJni) { 412 size_t entryCount = pRefTable->capacity(); 413 if (entryCount > 16) { 414 LOGW("Warning: more than 16 JNI local references: %d (most recent was a %s)", entryCount, obj->clazz->descriptor); 415 pRefTable->dump("JNI local"); 416 dvmDumpThread(dvmThreadSelf(), false); 417 //dvmAbort(); 418 } 419 } 420 #endif 421 422 if (gDvmJni.workAroundAppJniBugs) { 423 // Hand out direct pointers to support broken old apps. 424 return reinterpret_cast<jobject>(obj); 425 } 426 return jobj; 427 } 428 429 /* 430 * Ensure that at least "capacity" references can be held in the local 431 * refs table of the current thread. 432 */ 433 static bool ensureLocalCapacity(JNIEnv* env, int capacity) { 434 IndirectRefTable* pRefTable = getLocalRefTable(env); 435 int numEntries = pRefTable->capacity(); 436 // TODO: this isn't quite right, since "numEntries" includes holes 437 return ((kJniLocalRefMax - numEntries) >= capacity); 438 } 439 440 /* 441 * Explicitly delete a reference from the local list. 442 */ 443 static void deleteLocalReference(JNIEnv* env, jobject jobj) { 444 if (jobj == NULL) { 445 return; 446 } 447 448 IndirectRefTable* pRefTable = getLocalRefTable(env); 449 void* curFrame = self(env)->interpSave.curFrame; 450 u4 cookie = SAVEAREA_FROM_FP(curFrame)->xtra.localRefCookie; 451 if (!pRefTable->remove(cookie, jobj)) { 452 /* 453 * Attempting to delete a local reference that is not in the 454 * topmost local reference frame is a no-op. DeleteLocalRef returns 455 * void and doesn't throw any exceptions, but we should probably 456 * complain about it so the user will notice that things aren't 457 * going quite the way they expect. 458 */ 459 LOGW("JNI WARNING: DeleteLocalRef(%p) failed to find entry", jobj); 460 } 461 } 462 463 /* 464 * Add a global reference for an object. 465 * 466 * We may add the same object more than once. Add/remove calls are paired, 467 * so it needs to appear on the list multiple times. 468 */ 469 static jobject addGlobalReference(Object* obj) { 470 if (obj == NULL) { 471 return NULL; 472 } 473 474 //LOGI("adding obj=%p", obj); 475 //dvmDumpThread(dvmThreadSelf(), false); 476 477 if (false && dvmIsClassObject((Object*)obj)) { 478 ClassObject* clazz = (ClassObject*) obj; 479 LOGI("-------"); 480 LOGI("Adding global ref on class %s", clazz->descriptor); 481 dvmDumpThread(dvmThreadSelf(), false); 482 } 483 if (false && ((Object*)obj)->clazz == gDvm.classJavaLangString) { 484 StringObject* strObj = (StringObject*) obj; 485 char* str = dvmCreateCstrFromString(strObj); 486 if (strcmp(str, "sync-response") == 0) { 487 LOGI("-------"); 488 LOGI("Adding global ref on string '%s'", str); 489 dvmDumpThread(dvmThreadSelf(), false); 490 //dvmAbort(); 491 } 492 free(str); 493 } 494 if (false && ((Object*)obj)->clazz == gDvm.classArrayByte) { 495 ArrayObject* arrayObj = (ArrayObject*) obj; 496 if (arrayObj->length == 8192 /*&& 497 dvmReferenceTableEntries(&gDvm.jniGlobalRefTable) > 400*/) 498 { 499 LOGI("Adding global ref on byte array %p (len=%d)", 500 arrayObj, arrayObj->length); 501 dvmDumpThread(dvmThreadSelf(), false); 502 } 503 } 504 505 ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock); 506 507 /* 508 * Throwing an exception on failure is problematic, because JNI code 509 * may not be expecting an exception, and things sort of cascade. We 510 * want to have a hard limit to catch leaks during debugging, but this 511 * otherwise needs to expand until memory is consumed. As a practical 512 * matter, if we have many thousands of global references, chances are 513 * we're either leaking global ref table entries or we're going to 514 * run out of space in the GC heap. 515 */ 516 jobject jobj = (jobject) gDvm.jniGlobalRefTable.add(IRT_FIRST_SEGMENT, obj); 517 if (jobj == NULL) { 518 gDvm.jniGlobalRefTable.dump("JNI global"); 519 LOGE("Failed adding to JNI global ref table (%zd entries)", 520 gDvm.jniGlobalRefTable.capacity()); 521 dvmAbort(); 522 } 523 524 LOGVV("GREF add %p (%s.%s)", obj, 525 dvmGetCurrentJNIMethod()->clazz->descriptor, 526 dvmGetCurrentJNIMethod()->name); 527 528 /* GREF usage tracking; should probably be disabled for production env */ 529 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) { 530 int count = gDvm.jniGlobalRefTable.capacity(); 531 // TODO: adjust for "holes" 532 if (count > gDvm.jniGlobalRefHiMark) { 533 LOGD("GREF has increased to %d", count); 534 gDvm.jniGlobalRefHiMark += kGrefWaterInterval; 535 gDvm.jniGlobalRefLoMark += kGrefWaterInterval; 536 537 /* watch for "excessive" use; not generally appropriate */ 538 if (count >= gDvm.jniGrefLimit) { 539 if (gDvmJni.warnOnly) { 540 LOGW("Excessive JNI global references (%d)", count); 541 } else { 542 gDvm.jniGlobalRefTable.dump("JNI global"); 543 LOGE("Excessive JNI global references (%d)", count); 544 dvmAbort(); 545 } 546 } 547 } 548 } 549 return jobj; 550 } 551 552 static jobject addWeakGlobalReference(Object* obj) { 553 if (obj == NULL) { 554 return NULL; 555 } 556 557 ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock); 558 IndirectRefTable *table = &gDvm.jniWeakGlobalRefTable; 559 jobject jobj = (jobject) table->add(IRT_FIRST_SEGMENT, obj); 560 if (jobj == NULL) { 561 LOGE("Failed adding to JNI weak global ref table (%zd entries)", table->capacity()); 562 } 563 return jobj; 564 } 565 566 static void deleteWeakGlobalReference(jobject jobj) { 567 if (jobj == NULL) { 568 return; 569 } 570 571 ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock); 572 IndirectRefTable *table = &gDvm.jniWeakGlobalRefTable; 573 if (!table->remove(IRT_FIRST_SEGMENT, jobj)) { 574 LOGW("JNI: DeleteWeakGlobalRef(%p) failed to find entry", jobj); 575 } 576 } 577 578 /* 579 * Remove a global reference. In most cases it's the entry most recently 580 * added, which makes this pretty quick. 581 * 582 * Thought: if it's not the most recent entry, just null it out. When we 583 * fill up, do a compaction pass before we expand the list. 584 */ 585 static void deleteGlobalReference(jobject jobj) { 586 if (jobj == NULL) { 587 return; 588 } 589 590 ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock); 591 if (!gDvm.jniGlobalRefTable.remove(IRT_FIRST_SEGMENT, jobj)) { 592 LOGW("JNI: DeleteGlobalRef(%p) failed to find entry", jobj); 593 return; 594 } 595 596 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) { 597 int count = gDvm.jniGlobalRefTable.capacity(); 598 // TODO: not quite right, need to subtract holes 599 if (count < gDvm.jniGlobalRefLoMark) { 600 LOGD("GREF has decreased to %d", count); 601 gDvm.jniGlobalRefHiMark -= kGrefWaterInterval; 602 gDvm.jniGlobalRefLoMark -= kGrefWaterInterval; 603 } 604 } 605 } 606 607 /* 608 * Objects don't currently move, so we just need to create a reference 609 * that will ensure the array object isn't collected. 610 * 611 * We use a separate reference table, which is part of the GC root set. 612 */ 613 static void pinPrimitiveArray(ArrayObject* arrayObj) { 614 if (arrayObj == NULL) { 615 return; 616 } 617 618 ScopedPthreadMutexLock lock(&gDvm.jniPinRefLock); 619 620 if (!dvmAddToReferenceTable(&gDvm.jniPinRefTable, (Object*)arrayObj)) { 621 dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array"); 622 LOGE("Failed adding to JNI pinned array ref table (%d entries)", 623 (int) dvmReferenceTableEntries(&gDvm.jniPinRefTable)); 624 dvmDumpThread(dvmThreadSelf(), false); 625 dvmAbort(); 626 } 627 628 /* 629 * If we're watching global ref usage, also keep an eye on these. 630 * 631 * The total number of pinned primitive arrays should be pretty small. 632 * A single array should not be pinned more than once or twice; any 633 * more than that is a strong indicator that a Release function is 634 * not being called. 635 */ 636 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) { 637 int count = 0; 638 Object** ppObj = gDvm.jniPinRefTable.table; 639 while (ppObj < gDvm.jniPinRefTable.nextEntry) { 640 if (*ppObj++ == (Object*) arrayObj) 641 count++; 642 } 643 644 if (count > kPinComplainThreshold) { 645 LOGW("JNI: pin count on array %p (%s) is now %d", 646 arrayObj, arrayObj->clazz->descriptor, count); 647 /* keep going */ 648 } 649 } 650 } 651 652 /* 653 * Un-pin the array object. If an object was pinned twice, it must be 654 * unpinned twice before it's free to move. 655 */ 656 static void unpinPrimitiveArray(ArrayObject* arrayObj) { 657 if (arrayObj == NULL) { 658 return; 659 } 660 661 ScopedPthreadMutexLock lock(&gDvm.jniPinRefLock); 662 if (!dvmRemoveFromReferenceTable(&gDvm.jniPinRefTable, 663 gDvm.jniPinRefTable.table, (Object*) arrayObj)) 664 { 665 LOGW("JNI: unpinPrimitiveArray(%p) failed to find entry (valid=%d)", 666 arrayObj, dvmIsHeapAddress((Object*) arrayObj)); 667 return; 668 } 669 } 670 671 /* 672 * Dump the contents of the JNI reference tables to the log file. 673 * 674 * We only dump the local refs associated with the current thread. 675 */ 676 void dvmDumpJniReferenceTables() { 677 Thread* self = dvmThreadSelf(); 678 JNIEnv* env = self->jniEnv; 679 IndirectRefTable* pLocalRefs = getLocalRefTable(env); 680 pLocalRefs->dump("JNI local"); 681 gDvm.jniGlobalRefTable.dump("JNI global"); 682 dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array"); 683 } 684 685 /* 686 * Verify that a reference passed in from native code is one that the 687 * code is allowed to have. 688 * 689 * It's okay for native code to pass us a reference that: 690 * - was passed in as an argument when invoked by native code (and hence 691 * is in the JNI local refs table) 692 * - was returned to it from JNI (and is now in the local refs table) 693 * - is present in the JNI global refs table 694 * 695 * Used by -Xcheck:jni and GetObjectRefType. 696 */ 697 jobjectRefType dvmGetJNIRefType(JNIEnv* env, jobject jobj) { 698 /* 699 * IndirectRefKind is currently defined as an exact match of 700 * jobjectRefType, so this is easy. We have to decode it to determine 701 * if it's a valid reference and not merely valid-looking. 702 */ 703 assert(jobj != NULL); 704 705 Object* obj = dvmDecodeIndirectRef(env, jobj); 706 if (obj == reinterpret_cast<Object*>(jobj) && gDvmJni.workAroundAppJniBugs) { 707 // If we're handing out direct pointers, check whether 'jobj' is a direct reference 708 // to a local reference. 709 return getLocalRefTable(env)->contains(jobj) ? JNILocalRefType : JNIInvalidRefType; 710 } else if (obj == kInvalidIndirectRefObject) { 711 return JNIInvalidRefType; 712 } else { 713 return (jobjectRefType) indirectRefKind(jobj); 714 } 715 } 716 717 static void dumpMethods(Method* methods, size_t methodCount, const char* name) { 718 size_t i; 719 for (i = 0; i < methodCount; ++i) { 720 Method* method = &methods[i]; 721 if (strcmp(name, method->name) == 0) { 722 char* desc = dexProtoCopyMethodDescriptor(&method->prototype); 723 LOGE("Candidate: %s.%s:%s", method->clazz->descriptor, name, desc); 724 free(desc); 725 } 726 } 727 } 728 729 static void dumpCandidateMethods(ClassObject* clazz, const char* methodName, const char* signature) { 730 LOGE("ERROR: couldn't find native method"); 731 LOGE("Requested: %s.%s:%s", clazz->descriptor, methodName, signature); 732 dumpMethods(clazz->virtualMethods, clazz->virtualMethodCount, methodName); 733 dumpMethods(clazz->directMethods, clazz->directMethodCount, methodName); 734 } 735 736 /* 737 * Register a method that uses JNI calling conventions. 738 */ 739 static bool dvmRegisterJNIMethod(ClassObject* clazz, const char* methodName, 740 const char* signature, void* fnPtr) 741 { 742 if (fnPtr == NULL) { 743 return false; 744 } 745 746 // If a signature starts with a '!', we take that as a sign that the native code doesn't 747 // need the extra JNI arguments (the JNIEnv* and the jclass). 748 bool fastJni = false; 749 if (*signature == '!') { 750 fastJni = true; 751 ++signature; 752 LOGV("fast JNI method %s.%s:%s detected", clazz->descriptor, methodName, signature); 753 } 754 755 Method* method = dvmFindDirectMethodByDescriptor(clazz, methodName, signature); 756 if (method == NULL) { 757 method = dvmFindVirtualMethodByDescriptor(clazz, methodName, signature); 758 } 759 if (method == NULL) { 760 dumpCandidateMethods(clazz, methodName, signature); 761 return false; 762 } 763 764 if (!dvmIsNativeMethod(method)) { 765 LOGW("Unable to register: not native: %s.%s:%s", clazz->descriptor, methodName, signature); 766 return false; 767 } 768 769 if (fastJni) { 770 // In this case, we have extra constraints to check... 771 if (dvmIsSynchronizedMethod(method)) { 772 // Synchronization is usually provided by the JNI bridge, 773 // but we won't have one. 774 LOGE("fast JNI method %s.%s:%s cannot be synchronized", 775 clazz->descriptor, methodName, signature); 776 return false; 777 } 778 if (!dvmIsStaticMethod(method)) { 779 // There's no real reason for this constraint, but since we won't 780 // be supplying a JNIEnv* or a jobject 'this', you're effectively 781 // static anyway, so it seems clearer to say so. 782 LOGE("fast JNI method %s.%s:%s cannot be non-static", 783 clazz->descriptor, methodName, signature); 784 return false; 785 } 786 } 787 788 if (method->nativeFunc != dvmResolveNativeMethod) { 789 /* this is allowed, but unusual */ 790 LOGV("Note: %s.%s:%s was already registered", clazz->descriptor, methodName, signature); 791 } 792 793 method->fastJni = fastJni; 794 dvmUseJNIBridge(method, fnPtr); 795 796 LOGV("JNI-registered %s.%s:%s", clazz->descriptor, methodName, signature); 797 return true; 798 } 799 800 static const char* builtInPrefixes[] = { 801 "Landroid/", 802 "Lcom/android/", 803 "Lcom/google/android/", 804 "Ldalvik/", 805 "Ljava/", 806 "Ljavax/", 807 "Llibcore/", 808 "Lorg/apache/harmony/", 809 }; 810 811 static bool shouldTrace(Method* method) { 812 const char* className = method->clazz->descriptor; 813 // Return true if the -Xjnitrace setting implies we should trace 'method'. 814 if (gDvm.jniTrace && strstr(className, gDvm.jniTrace)) { 815 return true; 816 } 817 // Return true if we're trying to log all third-party JNI activity and 'method' doesn't look 818 // like part of Android. 819 if (gDvmJni.logThirdPartyJni) { 820 for (size_t i = 0; i < NELEM(builtInPrefixes); ++i) { 821 if (strstr(className, builtInPrefixes[i]) == className) { 822 return false; 823 } 824 } 825 return true; 826 } 827 return false; 828 } 829 830 /* 831 * Point "method->nativeFunc" at the JNI bridge, and overload "method->insns" 832 * to point at the actual function. 833 */ 834 void dvmUseJNIBridge(Method* method, void* func) { 835 method->shouldTrace = shouldTrace(method); 836 837 // Does the method take any reference arguments? 838 method->noRef = true; 839 const char* cp = method->shorty; 840 while (*++cp != '\0') { // Pre-increment to skip return type. 841 if (*cp == 'L') { 842 method->noRef = false; 843 break; 844 } 845 } 846 847 DalvikBridgeFunc bridge = gDvmJni.useCheckJni ? dvmCheckCallJNIMethod : dvmCallJNIMethod; 848 dvmSetNativeFunc(method, bridge, (const u2*) func); 849 } 850 851 // TODO: rewrite this to share code with CheckJNI's tracing... 852 static void appendValue(char type, const JValue value, char* buf, size_t n, bool appendComma) 853 { 854 size_t len = strlen(buf); 855 if (len >= n - 32) { // 32 should be longer than anything we could append. 856 buf[len - 1] = '.'; 857 buf[len - 2] = '.'; 858 buf[len - 3] = '.'; 859 return; 860 } 861 char* p = buf + len; 862 switch (type) { 863 case 'B': 864 if (value.b >= 0 && value.b < 10) { 865 sprintf(p, "%d", value.b); 866 } else { 867 sprintf(p, "%#x (%d)", value.b, value.b); 868 } 869 break; 870 case 'C': 871 if (value.c < 0x7f && value.c >= ' ') { 872 sprintf(p, "U+%x ('%c')", value.c, value.c); 873 } else { 874 sprintf(p, "U+%x", value.c); 875 } 876 break; 877 case 'D': 878 sprintf(p, "%g", value.d); 879 break; 880 case 'F': 881 sprintf(p, "%g", value.f); 882 break; 883 case 'I': 884 sprintf(p, "%d", value.i); 885 break; 886 case 'L': 887 sprintf(p, "%#x", value.i); 888 break; 889 case 'J': 890 sprintf(p, "%lld", value.j); 891 break; 892 case 'S': 893 sprintf(p, "%d", value.s); 894 break; 895 case 'V': 896 strcpy(p, "void"); 897 break; 898 case 'Z': 899 strcpy(p, value.z ? "true" : "false"); 900 break; 901 default: 902 sprintf(p, "unknown type '%c'", type); 903 break; 904 } 905 906 if (appendComma) { 907 strcat(p, ", "); 908 } 909 } 910 911 static void logNativeMethodEntry(const Method* method, const u4* args) 912 { 913 char thisString[32] = { 0 }; 914 const u4* sp = args; 915 if (!dvmIsStaticMethod(method)) { 916 sprintf(thisString, "this=0x%08x ", *sp++); 917 } 918 919 char argsString[128]= { 0 }; 920 const char* desc = &method->shorty[1]; 921 while (*desc != '\0') { 922 char argType = *desc++; 923 JValue value; 924 if (argType == 'D' || argType == 'J') { 925 value.j = dvmGetArgLong(sp, 0); 926 sp += 2; 927 } else { 928 value.i = *sp++; 929 } 930 appendValue(argType, value, argsString, sizeof(argsString), 931 *desc != '\0'); 932 } 933 934 std::string className(dvmHumanReadableDescriptor(method->clazz->descriptor)); 935 char* signature = dexProtoCopyMethodDescriptor(&method->prototype); 936 LOGI("-> %s %s%s %s(%s)", className.c_str(), method->name, signature, thisString, argsString); 937 free(signature); 938 } 939 940 static void logNativeMethodExit(const Method* method, Thread* self, const JValue returnValue) 941 { 942 std::string className(dvmHumanReadableDescriptor(method->clazz->descriptor)); 943 char* signature = dexProtoCopyMethodDescriptor(&method->prototype); 944 if (dvmCheckException(self)) { 945 Object* exception = dvmGetException(self); 946 std::string exceptionClassName(dvmHumanReadableDescriptor(exception->clazz->descriptor)); 947 LOGI("<- %s %s%s threw %s", className.c_str(), 948 method->name, signature, exceptionClassName.c_str()); 949 } else { 950 char returnValueString[128] = { 0 }; 951 char returnType = method->shorty[0]; 952 appendValue(returnType, returnValue, returnValueString, sizeof(returnValueString), false); 953 LOGI("<- %s %s%s returned %s", className.c_str(), 954 method->name, signature, returnValueString); 955 } 956 free(signature); 957 } 958 959 /* 960 * Get the method currently being executed by examining the interp stack. 961 */ 962 const Method* dvmGetCurrentJNIMethod() { 963 assert(dvmThreadSelf() != NULL); 964 965 void* fp = dvmThreadSelf()->interpSave.curFrame; 966 const Method* meth = SAVEAREA_FROM_FP(fp)->method; 967 968 assert(meth != NULL); 969 assert(dvmIsNativeMethod(meth)); 970 return meth; 971 } 972 973 /* 974 * Track a JNI MonitorEnter in the current thread. 975 * 976 * The goal is to be able to "implicitly" release all JNI-held monitors 977 * when the thread detaches. 978 * 979 * Monitors may be entered multiple times, so we add a new entry for each 980 * enter call. It would be more efficient to keep a counter. At present 981 * there's no real motivation to improve this however. 982 */ 983 static void trackMonitorEnter(Thread* self, Object* obj) { 984 static const int kInitialSize = 16; 985 ReferenceTable* refTable = &self->jniMonitorRefTable; 986 987 /* init table on first use */ 988 if (refTable->table == NULL) { 989 assert(refTable->maxEntries == 0); 990 991 if (!dvmInitReferenceTable(refTable, kInitialSize, INT_MAX)) { 992 LOGE("Unable to initialize monitor tracking table"); 993 dvmAbort(); 994 } 995 } 996 997 if (!dvmAddToReferenceTable(refTable, obj)) { 998 /* ran out of memory? could throw exception instead */ 999 LOGE("Unable to add entry to monitor tracking table"); 1000 dvmAbort(); 1001 } else { 1002 LOGVV("--- added monitor %p", obj); 1003 } 1004 } 1005 1006 /* 1007 * Track a JNI MonitorExit in the current thread. 1008 */ 1009 static void trackMonitorExit(Thread* self, Object* obj) { 1010 ReferenceTable* pRefTable = &self->jniMonitorRefTable; 1011 1012 if (!dvmRemoveFromReferenceTable(pRefTable, pRefTable->table, obj)) { 1013 LOGE("JNI monitor %p not found in tracking list", obj); 1014 /* keep going? */ 1015 } else { 1016 LOGVV("--- removed monitor %p", obj); 1017 } 1018 } 1019 1020 /* 1021 * Release all monitors held by the jniMonitorRefTable list. 1022 */ 1023 void dvmReleaseJniMonitors(Thread* self) { 1024 ReferenceTable* pRefTable = &self->jniMonitorRefTable; 1025 Object** top = pRefTable->table; 1026 1027 if (top == NULL) { 1028 return; 1029 } 1030 Object** ptr = pRefTable->nextEntry; 1031 while (--ptr >= top) { 1032 if (!dvmUnlockObject(self, *ptr)) { 1033 LOGW("Unable to unlock monitor %p at thread detach", *ptr); 1034 } else { 1035 LOGVV("--- detach-releasing monitor %p", *ptr); 1036 } 1037 } 1038 1039 /* zap it */ 1040 pRefTable->nextEntry = pRefTable->table; 1041 } 1042 1043 /* 1044 * Determine if the specified class can be instantiated from JNI. This 1045 * is used by AllocObject / NewObject, which are documented as throwing 1046 * an exception for abstract and interface classes, and not accepting 1047 * array classes. We also want to reject attempts to create new Class 1048 * objects, since only DefineClass should do that. 1049 */ 1050 static bool canAllocClass(ClassObject* clazz) { 1051 if (dvmIsAbstractClass(clazz) || dvmIsInterfaceClass(clazz)) { 1052 /* JNI spec defines what this throws */ 1053 dvmThrowInstantiationException(clazz, "abstract class or interface"); 1054 return false; 1055 } else if (dvmIsArrayClass(clazz) || dvmIsTheClassClass(clazz)) { 1056 /* spec says "must not" for arrays, ignores Class */ 1057 dvmThrowInstantiationException(clazz, "wrong JNI function"); 1058 return false; 1059 } 1060 return true; 1061 } 1062 1063 1064 /* 1065 * =========================================================================== 1066 * JNI call bridge 1067 * =========================================================================== 1068 */ 1069 1070 /* 1071 * The functions here form a bridge between interpreted code and JNI native 1072 * functions. The basic task is to convert an array of primitives and 1073 * references into C-style function arguments. This is architecture-specific 1074 * and usually requires help from assembly code. 1075 * 1076 * The bridge takes four arguments: the array of parameters, a place to 1077 * store the function result (if any), the method to call, and a pointer 1078 * to the current thread. 1079 * 1080 * These functions aren't called directly from elsewhere in the VM. 1081 * A pointer in the Method struct points to one of these, and when a native 1082 * method is invoked the interpreter jumps to it. 1083 * 1084 * (The "internal native" methods are invoked the same way, but instead 1085 * of calling through a bridge, the target method is called directly.) 1086 * 1087 * The "args" array should not be modified, but we do so anyway for 1088 * performance reasons. We know that it points to the "outs" area on 1089 * the current method's interpreted stack. This area is ignored by the 1090 * precise GC, because there is no register map for a native method (for 1091 * an interpreted method the args would be listed in the argument set). 1092 * We know all of the values exist elsewhere on the interpreted stack, 1093 * because the method call setup copies them right before making the call, 1094 * so we don't have to worry about concealing stuff from the GC. 1095 * 1096 * If we don't want to modify "args", we either have to create a local 1097 * copy and modify it before calling dvmPlatformInvoke, or we have to do 1098 * the local reference replacement within dvmPlatformInvoke. The latter 1099 * has some performance advantages, though if we can inline the local 1100 * reference adds we may win when there's a lot of reference args (unless 1101 * we want to code up some local ref table manipulation in assembly. 1102 */ 1103 1104 /* 1105 * If necessary, convert the value in pResult from a local/global reference 1106 * to an object pointer. 1107 * 1108 * If the returned reference is invalid, kInvalidIndirectRefObject will 1109 * be returned in pResult. 1110 */ 1111 static inline void convertReferenceResult(JNIEnv* env, JValue* pResult, 1112 const Method* method, Thread* self) 1113 { 1114 if (method->shorty[0] == 'L' && !dvmCheckException(self) && pResult->l != NULL) { 1115 pResult->l = dvmDecodeIndirectRef(env, (jobject) pResult->l); 1116 } 1117 } 1118 1119 /* 1120 * General form, handles all cases. 1121 */ 1122 void dvmCallJNIMethod(const u4* args, JValue* pResult, const Method* method, Thread* self) { 1123 u4* modArgs = (u4*) args; 1124 jclass staticMethodClass = NULL; 1125 JNIEnv* env = self->jniEnv; 1126 1127 bool isSynchronized = dvmIsSynchronizedMethod(method); 1128 Object* lockObj; 1129 1130 //LOGI("JNI calling %p (%s.%s:%s):", method->insns, 1131 // method->clazz->descriptor, method->name, method->shorty); 1132 1133 /* 1134 * Walk the argument list, creating local references for appropriate 1135 * arguments. 1136 */ 1137 int idx = 0; 1138 if (dvmIsStaticMethod(method)) { 1139 lockObj = (Object*) method->clazz; 1140 1141 /* add the class object we pass in */ 1142 staticMethodClass = (jclass) addLocalReference(env, (Object*) method->clazz); 1143 if (staticMethodClass == NULL) { 1144 assert(dvmCheckException(self)); 1145 return; 1146 } 1147 } else { 1148 lockObj = (Object*) args[0]; 1149 1150 /* add "this" */ 1151 jobject thisObj = addLocalReference(env, (Object*) modArgs[0]); 1152 if (thisObj == NULL) { 1153 assert(dvmCheckException(self)); 1154 return; 1155 } 1156 modArgs[idx] = (u4) thisObj; 1157 idx = 1; 1158 } 1159 1160 if (!method->noRef) { 1161 const char* shorty = &method->shorty[1]; /* skip return type */ 1162 while (*shorty != '\0') { 1163 switch (*shorty++) { 1164 case 'L': 1165 //LOGI(" local %d: 0x%08x", idx, modArgs[idx]); 1166 if (modArgs[idx] != 0) { 1167 jobject argObj = addLocalReference(env, (Object*) modArgs[idx]); 1168 if (argObj == NULL) { 1169 assert(dvmCheckException(self)); 1170 return; 1171 } 1172 modArgs[idx] = (u4) argObj; 1173 } 1174 break; 1175 case 'D': 1176 case 'J': 1177 idx++; 1178 break; 1179 default: 1180 /* Z B C S I -- do nothing */ 1181 break; 1182 } 1183 idx++; 1184 } 1185 } 1186 1187 if (method->shouldTrace) { 1188 logNativeMethodEntry(method, args); 1189 } 1190 if (isSynchronized) { 1191 dvmLockObject(self, lockObj); 1192 } 1193 1194 ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_NATIVE); 1195 1196 ANDROID_MEMBAR_FULL(); /* guarantee ordering on method->insns */ 1197 assert(method->insns != NULL); 1198 1199 COMPUTE_STACK_SUM(self); 1200 dvmPlatformInvoke(method->fastJni ? NULL : env, 1201 (ClassObject*) staticMethodClass, 1202 method->jniArgInfo, method->insSize, modArgs, method->shorty, 1203 (void*) method->insns, pResult); 1204 CHECK_STACK_SUM(self); 1205 1206 dvmChangeStatus(self, oldStatus); 1207 1208 convertReferenceResult(env, pResult, method, self); 1209 1210 if (isSynchronized) { 1211 dvmUnlockObject(self, lockObj); 1212 } 1213 if (method->shouldTrace) { 1214 logNativeMethodExit(method, self, *pResult); 1215 } 1216 } 1217 1218 /* 1219 * Extract the return type enum from the "jniArgInfo" field. 1220 */ 1221 DalvikJniReturnType dvmGetArgInfoReturnType(int jniArgInfo) { 1222 return static_cast<DalvikJniReturnType>((jniArgInfo & DALVIK_JNI_RETURN_MASK) >> DALVIK_JNI_RETURN_SHIFT); 1223 } 1224 1225 /* 1226 * =========================================================================== 1227 * JNI implementation 1228 * =========================================================================== 1229 */ 1230 1231 /* 1232 * Return the version of the native method interface. 1233 */ 1234 static jint GetVersion(JNIEnv* env) { 1235 /* 1236 * There is absolutely no need to toggle the mode for correct behavior. 1237 * However, it does provide native code with a simple "suspend self 1238 * if necessary" call. 1239 */ 1240 ScopedJniThreadState ts(env); 1241 return JNI_VERSION_1_6; 1242 } 1243 1244 /* 1245 * Create a new class from a bag of bytes. 1246 * 1247 * This is not currently supported within Dalvik. 1248 */ 1249 static jclass DefineClass(JNIEnv* env, const char *name, jobject loader, 1250 const jbyte* buf, jsize bufLen) 1251 { 1252 UNUSED_PARAMETER(name); 1253 UNUSED_PARAMETER(loader); 1254 UNUSED_PARAMETER(buf); 1255 UNUSED_PARAMETER(bufLen); 1256 1257 ScopedJniThreadState ts(env); 1258 LOGW("JNI DefineClass is not supported"); 1259 return NULL; 1260 } 1261 1262 /* 1263 * Find a class by name. 1264 * 1265 * We have to use the "no init" version of FindClass here, because we might 1266 * be getting the class prior to registering native methods that will be 1267 * used in <clinit>. 1268 * 1269 * We need to get the class loader associated with the current native 1270 * method. If there is no native method, e.g. we're calling this from native 1271 * code right after creating the VM, the spec says we need to use the class 1272 * loader returned by "ClassLoader.getBaseClassLoader". There is no such 1273 * method, but it's likely they meant ClassLoader.getSystemClassLoader. 1274 * We can't get that until after the VM has initialized though. 1275 */ 1276 static jclass FindClass(JNIEnv* env, const char* name) { 1277 ScopedJniThreadState ts(env); 1278 1279 const Method* thisMethod = dvmGetCurrentJNIMethod(); 1280 assert(thisMethod != NULL); 1281 1282 Object* loader; 1283 Object* trackedLoader = NULL; 1284 if (ts.self()->classLoaderOverride != NULL) { 1285 /* hack for JNI_OnLoad */ 1286 assert(strcmp(thisMethod->name, "nativeLoad") == 0); 1287 loader = ts.self()->classLoaderOverride; 1288 } else if (thisMethod == gDvm.methDalvikSystemNativeStart_main || 1289 thisMethod == gDvm.methDalvikSystemNativeStart_run) { 1290 /* start point of invocation interface */ 1291 if (!gDvm.initializing) { 1292 loader = trackedLoader = dvmGetSystemClassLoader(); 1293 } else { 1294 loader = NULL; 1295 } 1296 } else { 1297 loader = thisMethod->clazz->classLoader; 1298 } 1299 1300 char* descriptor = dvmNameToDescriptor(name); 1301 if (descriptor == NULL) { 1302 return NULL; 1303 } 1304 ClassObject* clazz = dvmFindClassNoInit(descriptor, loader); 1305 free(descriptor); 1306 1307 jclass jclazz = (jclass) addLocalReference(env, (Object*) clazz); 1308 dvmReleaseTrackedAlloc(trackedLoader, ts.self()); 1309 return jclazz; 1310 } 1311 1312 /* 1313 * Return the superclass of a class. 1314 */ 1315 static jclass GetSuperclass(JNIEnv* env, jclass jclazz) { 1316 ScopedJniThreadState ts(env); 1317 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1318 return (jclass) addLocalReference(env, (Object*)clazz->super); 1319 } 1320 1321 /* 1322 * Determine whether an object of clazz1 can be safely cast to clazz2. 1323 * 1324 * Like IsInstanceOf, but with a pair of class objects instead of obj+class. 1325 */ 1326 static jboolean IsAssignableFrom(JNIEnv* env, jclass jclazz1, jclass jclazz2) { 1327 ScopedJniThreadState ts(env); 1328 ClassObject* clazz1 = (ClassObject*) dvmDecodeIndirectRef(env, jclazz1); 1329 ClassObject* clazz2 = (ClassObject*) dvmDecodeIndirectRef(env, jclazz2); 1330 return dvmInstanceof(clazz1, clazz2); 1331 } 1332 1333 /* 1334 * Given a java.lang.reflect.Method or .Constructor, return a methodID. 1335 */ 1336 static jmethodID FromReflectedMethod(JNIEnv* env, jobject jmethod) { 1337 ScopedJniThreadState ts(env); 1338 Object* method = dvmDecodeIndirectRef(env, jmethod); 1339 return (jmethodID) dvmGetMethodFromReflectObj(method); 1340 } 1341 1342 /* 1343 * Given a java.lang.reflect.Field, return a fieldID. 1344 */ 1345 static jfieldID FromReflectedField(JNIEnv* env, jobject jfield) { 1346 ScopedJniThreadState ts(env); 1347 Object* field = dvmDecodeIndirectRef(env, jfield); 1348 return (jfieldID) dvmGetFieldFromReflectObj(field); 1349 } 1350 1351 /* 1352 * Convert a methodID to a java.lang.reflect.Method or .Constructor. 1353 * 1354 * (The "isStatic" field does not appear in the spec.) 1355 * 1356 * Throws OutOfMemory and returns NULL on failure. 1357 */ 1358 static jobject ToReflectedMethod(JNIEnv* env, jclass jcls, jmethodID methodID, jboolean isStatic) { 1359 ScopedJniThreadState ts(env); 1360 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jcls); 1361 Object* obj = dvmCreateReflectObjForMethod(clazz, (Method*) methodID); 1362 dvmReleaseTrackedAlloc(obj, NULL); 1363 return addLocalReference(env, obj); 1364 } 1365 1366 /* 1367 * Convert a fieldID to a java.lang.reflect.Field. 1368 * 1369 * (The "isStatic" field does not appear in the spec.) 1370 * 1371 * Throws OutOfMemory and returns NULL on failure. 1372 */ 1373 static jobject ToReflectedField(JNIEnv* env, jclass jcls, jfieldID fieldID, jboolean isStatic) { 1374 ScopedJniThreadState ts(env); 1375 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jcls); 1376 Object* obj = dvmCreateReflectObjForField(clazz, (Field*) fieldID); 1377 dvmReleaseTrackedAlloc(obj, NULL); 1378 return addLocalReference(env, obj); 1379 } 1380 1381 /* 1382 * Take this exception and throw it. 1383 */ 1384 static jint Throw(JNIEnv* env, jthrowable jobj) { 1385 ScopedJniThreadState ts(env); 1386 if (jobj != NULL) { 1387 Object* obj = dvmDecodeIndirectRef(env, jobj); 1388 dvmSetException(ts.self(), obj); 1389 return JNI_OK; 1390 } 1391 return JNI_ERR; 1392 } 1393 1394 /* 1395 * Constructs an exception object from the specified class with the message 1396 * specified by "message", and throws it. 1397 */ 1398 static jint ThrowNew(JNIEnv* env, jclass jclazz, const char* message) { 1399 ScopedJniThreadState ts(env); 1400 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1401 dvmThrowException(clazz, message); 1402 // TODO: should return failure if this didn't work (e.g. OOM) 1403 return JNI_OK; 1404 } 1405 1406 /* 1407 * If an exception is being thrown, return the exception object. Otherwise, 1408 * return NULL. 1409 * 1410 * TODO: if there is no pending exception, we should be able to skip the 1411 * enter/exit checks. If we find one, we need to enter and then re-fetch 1412 * the exception (in case it got moved by a compacting GC). 1413 */ 1414 static jthrowable ExceptionOccurred(JNIEnv* env) { 1415 ScopedJniThreadState ts(env); 1416 Object* exception = dvmGetException(ts.self()); 1417 jthrowable localException = (jthrowable) addLocalReference(env, exception); 1418 if (localException == NULL && exception != NULL) { 1419 /* 1420 * We were unable to add a new local reference, and threw a new 1421 * exception. We can't return "exception", because it's not a 1422 * local reference. So we have to return NULL, indicating that 1423 * there was no exception, even though it's pretty much raining 1424 * exceptions in here. 1425 */ 1426 LOGW("JNI WARNING: addLocal/exception combo"); 1427 } 1428 return localException; 1429 } 1430 1431 /* 1432 * Print an exception and stack trace to stderr. 1433 */ 1434 static void ExceptionDescribe(JNIEnv* env) { 1435 ScopedJniThreadState ts(env); 1436 Object* exception = dvmGetException(ts.self()); 1437 if (exception != NULL) { 1438 dvmPrintExceptionStackTrace(); 1439 } else { 1440 LOGI("Odd: ExceptionDescribe called, but no exception pending"); 1441 } 1442 } 1443 1444 /* 1445 * Clear the exception currently being thrown. 1446 * 1447 * TODO: we should be able to skip the enter/exit stuff. 1448 */ 1449 static void ExceptionClear(JNIEnv* env) { 1450 ScopedJniThreadState ts(env); 1451 dvmClearException(ts.self()); 1452 } 1453 1454 /* 1455 * Kill the VM. This function does not return. 1456 */ 1457 static void FatalError(JNIEnv* env, const char* msg) { 1458 //dvmChangeStatus(NULL, THREAD_RUNNING); 1459 LOGE("JNI posting fatal error: %s", msg); 1460 dvmAbort(); 1461 } 1462 1463 /* 1464 * Push a new JNI frame on the stack, with a new set of locals. 1465 * 1466 * The new frame must have the same method pointer. (If for no other 1467 * reason than FindClass needs it to get the appropriate class loader.) 1468 */ 1469 static jint PushLocalFrame(JNIEnv* env, jint capacity) { 1470 ScopedJniThreadState ts(env); 1471 if (!ensureLocalCapacity(env, capacity) || 1472 !dvmPushLocalFrame(ts.self(), dvmGetCurrentJNIMethod())) 1473 { 1474 /* yes, OutOfMemoryError, not StackOverflowError */ 1475 dvmClearException(ts.self()); 1476 dvmThrowOutOfMemoryError("out of stack in JNI PushLocalFrame"); 1477 return JNI_ERR; 1478 } 1479 return JNI_OK; 1480 } 1481 1482 /* 1483 * Pop the local frame off. If "jresult" is not null, add it as a 1484 * local reference on the now-current frame. 1485 */ 1486 static jobject PopLocalFrame(JNIEnv* env, jobject jresult) { 1487 ScopedJniThreadState ts(env); 1488 Object* result = dvmDecodeIndirectRef(env, jresult); 1489 if (!dvmPopLocalFrame(ts.self())) { 1490 LOGW("JNI WARNING: too many PopLocalFrame calls"); 1491 dvmClearException(ts.self()); 1492 dvmThrowRuntimeException("too many PopLocalFrame calls"); 1493 } 1494 return addLocalReference(env, result); 1495 } 1496 1497 /* 1498 * Add a reference to the global list. 1499 */ 1500 static jobject NewGlobalRef(JNIEnv* env, jobject jobj) { 1501 ScopedJniThreadState ts(env); 1502 Object* obj = dvmDecodeIndirectRef(env, jobj); 1503 return addGlobalReference(obj); 1504 } 1505 1506 /* 1507 * Delete a reference from the global list. 1508 */ 1509 static void DeleteGlobalRef(JNIEnv* env, jobject jglobalRef) { 1510 ScopedJniThreadState ts(env); 1511 deleteGlobalReference(jglobalRef); 1512 } 1513 1514 1515 /* 1516 * Add a reference to the local list. 1517 */ 1518 static jobject NewLocalRef(JNIEnv* env, jobject jobj) { 1519 ScopedJniThreadState ts(env); 1520 Object* obj = dvmDecodeIndirectRef(env, jobj); 1521 return addLocalReference(env, obj); 1522 } 1523 1524 /* 1525 * Delete a reference from the local list. 1526 */ 1527 static void DeleteLocalRef(JNIEnv* env, jobject jlocalRef) { 1528 ScopedJniThreadState ts(env); 1529 deleteLocalReference(env, jlocalRef); 1530 } 1531 1532 /* 1533 * Ensure that the local references table can hold at least this many 1534 * references. 1535 */ 1536 static jint EnsureLocalCapacity(JNIEnv* env, jint capacity) { 1537 ScopedJniThreadState ts(env); 1538 bool okay = ensureLocalCapacity(env, capacity); 1539 if (!okay) { 1540 dvmThrowOutOfMemoryError("can't ensure local reference capacity"); 1541 } 1542 return okay ? 0 : -1; 1543 } 1544 1545 1546 /* 1547 * Determine whether two Object references refer to the same underlying object. 1548 */ 1549 static jboolean IsSameObject(JNIEnv* env, jobject jref1, jobject jref2) { 1550 ScopedJniThreadState ts(env); 1551 Object* obj1 = dvmDecodeIndirectRef(env, jref1); 1552 Object* obj2 = dvmDecodeIndirectRef(env, jref2); 1553 return (obj1 == obj2); 1554 } 1555 1556 /* 1557 * Allocate a new object without invoking any constructors. 1558 */ 1559 static jobject AllocObject(JNIEnv* env, jclass jclazz) { 1560 ScopedJniThreadState ts(env); 1561 1562 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1563 if (!canAllocClass(clazz) || 1564 (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) 1565 { 1566 assert(dvmCheckException(ts.self())); 1567 return NULL; 1568 } 1569 1570 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK); 1571 return addLocalReference(env, newObj); 1572 } 1573 1574 /* 1575 * Allocate a new object and invoke the supplied constructor. 1576 */ 1577 static jobject NewObject(JNIEnv* env, jclass jclazz, jmethodID methodID, ...) { 1578 ScopedJniThreadState ts(env); 1579 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1580 1581 if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) { 1582 assert(dvmCheckException(ts.self())); 1583 return NULL; 1584 } 1585 1586 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK); 1587 jobject result = addLocalReference(env, newObj); 1588 if (newObj != NULL) { 1589 JValue unused; 1590 va_list args; 1591 va_start(args, methodID); 1592 dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args); 1593 va_end(args); 1594 } 1595 return result; 1596 } 1597 1598 static jobject NewObjectV(JNIEnv* env, jclass jclazz, jmethodID methodID, va_list args) { 1599 ScopedJniThreadState ts(env); 1600 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1601 1602 if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) { 1603 assert(dvmCheckException(ts.self())); 1604 return NULL; 1605 } 1606 1607 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK); 1608 jobject result = addLocalReference(env, newObj); 1609 if (newObj != NULL) { 1610 JValue unused; 1611 dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args); 1612 } 1613 return result; 1614 } 1615 1616 static jobject NewObjectA(JNIEnv* env, jclass jclazz, jmethodID methodID, jvalue* args) { 1617 ScopedJniThreadState ts(env); 1618 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1619 1620 if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) { 1621 assert(dvmCheckException(ts.self())); 1622 return NULL; 1623 } 1624 1625 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK); 1626 jobject result = addLocalReference(env, newObj); 1627 if (newObj != NULL) { 1628 JValue unused; 1629 dvmCallMethodA(ts.self(), (Method*) methodID, newObj, true, &unused, args); 1630 } 1631 return result; 1632 } 1633 1634 /* 1635 * Returns the class of an object. 1636 * 1637 * JNI spec says: obj must not be NULL. 1638 */ 1639 static jclass GetObjectClass(JNIEnv* env, jobject jobj) { 1640 ScopedJniThreadState ts(env); 1641 1642 assert(jobj != NULL); 1643 1644 Object* obj = dvmDecodeIndirectRef(env, jobj); 1645 return (jclass) addLocalReference(env, (Object*) obj->clazz); 1646 } 1647 1648 /* 1649 * Determine whether "obj" is an instance of "clazz". 1650 */ 1651 static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass jclazz) { 1652 ScopedJniThreadState ts(env); 1653 1654 assert(jclazz != NULL); 1655 if (jobj == NULL) { 1656 return true; 1657 } 1658 1659 Object* obj = dvmDecodeIndirectRef(env, jobj); 1660 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1661 return dvmInstanceof(obj->clazz, clazz); 1662 } 1663 1664 /* 1665 * Get a method ID for an instance method. 1666 * 1667 * While Dalvik bytecode has distinct instructions for virtual, super, 1668 * static, direct, and interface method invocation, JNI only provides 1669 * two functions for acquiring a method ID. This call handles everything 1670 * but static methods. 1671 * 1672 * JNI defines <init> as an instance method, but Dalvik considers it a 1673 * "direct" method, so we have to special-case it here. 1674 * 1675 * Dalvik also puts all private methods into the "direct" list, so we 1676 * really need to just search both lists. 1677 */ 1678 static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) { 1679 ScopedJniThreadState ts(env); 1680 1681 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1682 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) { 1683 assert(dvmCheckException(ts.self())); 1684 } else if (dvmIsInterfaceClass(clazz)) { 1685 Method* meth = dvmFindInterfaceMethodHierByDescriptor(clazz, name, sig); 1686 if (meth == NULL) { 1687 dvmThrowExceptionFmt(gDvm.exNoSuchMethodError, 1688 "no method with name='%s' signature='%s' in interface %s", 1689 name, sig, clazz->descriptor); 1690 } 1691 return (jmethodID) meth; 1692 } 1693 Method* meth = dvmFindVirtualMethodHierByDescriptor(clazz, name, sig); 1694 if (meth == NULL) { 1695 /* search private methods and constructors; non-hierarchical */ 1696 meth = dvmFindDirectMethodByDescriptor(clazz, name, sig); 1697 } 1698 if (meth != NULL && dvmIsStaticMethod(meth)) { 1699 IF_LOGD() { 1700 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype); 1701 LOGD("GetMethodID: not returning static method %s.%s %s", 1702 clazz->descriptor, meth->name, desc); 1703 free(desc); 1704 } 1705 meth = NULL; 1706 } 1707 if (meth == NULL) { 1708 dvmThrowExceptionFmt(gDvm.exNoSuchMethodError, 1709 "no method with name='%s' signature='%s' in class %s", 1710 name, sig, clazz->descriptor); 1711 } else { 1712 /* 1713 * The method's class may not be the same as clazz, but if 1714 * it isn't this must be a virtual method and the class must 1715 * be a superclass (and, hence, already initialized). 1716 */ 1717 assert(dvmIsClassInitialized(meth->clazz) || dvmIsClassInitializing(meth->clazz)); 1718 } 1719 return (jmethodID) meth; 1720 } 1721 1722 /* 1723 * Get a field ID (instance fields). 1724 */ 1725 static jfieldID GetFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) { 1726 ScopedJniThreadState ts(env); 1727 1728 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1729 1730 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) { 1731 assert(dvmCheckException(ts.self())); 1732 return NULL; 1733 } 1734 1735 jfieldID id = (jfieldID) dvmFindInstanceFieldHier(clazz, name, sig); 1736 if (id == NULL) { 1737 dvmThrowExceptionFmt(gDvm.exNoSuchFieldError, 1738 "no field with name='%s' signature='%s' in class %s", 1739 name, sig, clazz->descriptor); 1740 } 1741 return id; 1742 } 1743 1744 /* 1745 * Get the method ID for a static method in a class. 1746 */ 1747 static jmethodID GetStaticMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) { 1748 ScopedJniThreadState ts(env); 1749 1750 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1751 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) { 1752 assert(dvmCheckException(ts.self())); 1753 return NULL; 1754 } 1755 1756 Method* meth = dvmFindDirectMethodHierByDescriptor(clazz, name, sig); 1757 1758 /* make sure it's static, not virtual+private */ 1759 if (meth != NULL && !dvmIsStaticMethod(meth)) { 1760 IF_LOGD() { 1761 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype); 1762 LOGD("GetStaticMethodID: not returning nonstatic method %s.%s %s", 1763 clazz->descriptor, meth->name, desc); 1764 free(desc); 1765 } 1766 meth = NULL; 1767 } 1768 1769 jmethodID id = (jmethodID) meth; 1770 if (id == NULL) { 1771 dvmThrowExceptionFmt(gDvm.exNoSuchMethodError, 1772 "no static method with name='%s' signature='%s' in class %s", 1773 name, sig, clazz->descriptor); 1774 } 1775 return id; 1776 } 1777 1778 /* 1779 * Get a field ID (static fields). 1780 */ 1781 static jfieldID GetStaticFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) { 1782 ScopedJniThreadState ts(env); 1783 1784 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 1785 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) { 1786 assert(dvmCheckException(ts.self())); 1787 return NULL; 1788 } 1789 1790 jfieldID id = (jfieldID) dvmFindStaticFieldHier(clazz, name, sig); 1791 if (id == NULL) { 1792 dvmThrowExceptionFmt(gDvm.exNoSuchFieldError, 1793 "no static field with name='%s' signature='%s' in class %s", 1794 name, sig, clazz->descriptor); 1795 } 1796 return id; 1797 } 1798 1799 /* 1800 * Get a static field. 1801 * 1802 * If we get an object reference, add it to the local refs list. 1803 */ 1804 #define GET_STATIC_TYPE_FIELD(_ctype, _jname, _isref) \ 1805 static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass jclazz, \ 1806 jfieldID fieldID) \ 1807 { \ 1808 UNUSED_PARAMETER(jclazz); \ 1809 ScopedJniThreadState ts(env); \ 1810 StaticField* sfield = (StaticField*) fieldID; \ 1811 _ctype value; \ 1812 if (dvmIsVolatileField(sfield)) { \ 1813 if (_isref) { /* only when _ctype==jobject */ \ 1814 Object* obj = dvmGetStaticFieldObjectVolatile(sfield); \ 1815 value = (_ctype)(u4)addLocalReference(env, obj); \ 1816 } else { \ 1817 value = (_ctype) dvmGetStaticField##_jname##Volatile(sfield);\ 1818 } \ 1819 } else { \ 1820 if (_isref) { \ 1821 Object* obj = dvmGetStaticFieldObject(sfield); \ 1822 value = (_ctype)(u4)addLocalReference(env, obj); \ 1823 } else { \ 1824 value = (_ctype) dvmGetStaticField##_jname(sfield); \ 1825 } \ 1826 } \ 1827 return value; \ 1828 } 1829 GET_STATIC_TYPE_FIELD(jobject, Object, true); 1830 GET_STATIC_TYPE_FIELD(jboolean, Boolean, false); 1831 GET_STATIC_TYPE_FIELD(jbyte, Byte, false); 1832 GET_STATIC_TYPE_FIELD(jchar, Char, false); 1833 GET_STATIC_TYPE_FIELD(jshort, Short, false); 1834 GET_STATIC_TYPE_FIELD(jint, Int, false); 1835 GET_STATIC_TYPE_FIELD(jlong, Long, false); 1836 GET_STATIC_TYPE_FIELD(jfloat, Float, false); 1837 GET_STATIC_TYPE_FIELD(jdouble, Double, false); 1838 1839 /* 1840 * Set a static field. 1841 */ 1842 #define SET_STATIC_TYPE_FIELD(_ctype, _ctype2, _jname, _isref) \ 1843 static void SetStatic##_jname##Field(JNIEnv* env, jclass jclazz, \ 1844 jfieldID fieldID, _ctype value) \ 1845 { \ 1846 UNUSED_PARAMETER(jclazz); \ 1847 ScopedJniThreadState ts(env); \ 1848 StaticField* sfield = (StaticField*) fieldID; \ 1849 if (dvmIsVolatileField(sfield)) { \ 1850 if (_isref) { /* only when _ctype==jobject */ \ 1851 Object* valObj = \ 1852 dvmDecodeIndirectRef(env, (jobject)(u4)value); \ 1853 dvmSetStaticFieldObjectVolatile(sfield, valObj); \ 1854 } else { \ 1855 dvmSetStaticField##_jname##Volatile(sfield, (_ctype2)value);\ 1856 } \ 1857 } else { \ 1858 if (_isref) { \ 1859 Object* valObj = \ 1860 dvmDecodeIndirectRef(env, (jobject)(u4)value); \ 1861 dvmSetStaticFieldObject(sfield, valObj); \ 1862 } else { \ 1863 dvmSetStaticField##_jname(sfield, (_ctype2)value); \ 1864 } \ 1865 } \ 1866 } 1867 SET_STATIC_TYPE_FIELD(jobject, Object*, Object, true); 1868 SET_STATIC_TYPE_FIELD(jboolean, bool, Boolean, false); 1869 SET_STATIC_TYPE_FIELD(jbyte, s1, Byte, false); 1870 SET_STATIC_TYPE_FIELD(jchar, u2, Char, false); 1871 SET_STATIC_TYPE_FIELD(jshort, s2, Short, false); 1872 SET_STATIC_TYPE_FIELD(jint, s4, Int, false); 1873 SET_STATIC_TYPE_FIELD(jlong, s8, Long, false); 1874 SET_STATIC_TYPE_FIELD(jfloat, float, Float, false); 1875 SET_STATIC_TYPE_FIELD(jdouble, double, Double, false); 1876 1877 /* 1878 * Get an instance field. 1879 * 1880 * If we get an object reference, add it to the local refs list. 1881 */ 1882 #define GET_TYPE_FIELD(_ctype, _jname, _isref) \ 1883 static _ctype Get##_jname##Field(JNIEnv* env, jobject jobj, \ 1884 jfieldID fieldID) \ 1885 { \ 1886 ScopedJniThreadState ts(env); \ 1887 Object* obj = dvmDecodeIndirectRef(env, jobj); \ 1888 InstField* field = (InstField*) fieldID; \ 1889 _ctype value; \ 1890 if (dvmIsVolatileField(field)) { \ 1891 if (_isref) { /* only when _ctype==jobject */ \ 1892 Object* valObj = \ 1893 dvmGetFieldObjectVolatile(obj, field->byteOffset); \ 1894 value = (_ctype)(u4)addLocalReference(env, valObj); \ 1895 } else { \ 1896 value = (_ctype) \ 1897 dvmGetField##_jname##Volatile(obj, field->byteOffset); \ 1898 } \ 1899 } else { \ 1900 if (_isref) { \ 1901 Object* valObj = dvmGetFieldObject(obj, field->byteOffset); \ 1902 value = (_ctype)(u4)addLocalReference(env, valObj); \ 1903 } else { \ 1904 value = (_ctype) dvmGetField##_jname(obj, field->byteOffset);\ 1905 } \ 1906 } \ 1907 return value; \ 1908 } 1909 GET_TYPE_FIELD(jobject, Object, true); 1910 GET_TYPE_FIELD(jboolean, Boolean, false); 1911 GET_TYPE_FIELD(jbyte, Byte, false); 1912 GET_TYPE_FIELD(jchar, Char, false); 1913 GET_TYPE_FIELD(jshort, Short, false); 1914 GET_TYPE_FIELD(jint, Int, false); 1915 GET_TYPE_FIELD(jlong, Long, false); 1916 GET_TYPE_FIELD(jfloat, Float, false); 1917 GET_TYPE_FIELD(jdouble, Double, false); 1918 1919 /* 1920 * Set an instance field. 1921 */ 1922 #define SET_TYPE_FIELD(_ctype, _ctype2, _jname, _isref) \ 1923 static void Set##_jname##Field(JNIEnv* env, jobject jobj, \ 1924 jfieldID fieldID, _ctype value) \ 1925 { \ 1926 ScopedJniThreadState ts(env); \ 1927 Object* obj = dvmDecodeIndirectRef(env, jobj); \ 1928 InstField* field = (InstField*) fieldID; \ 1929 if (dvmIsVolatileField(field)) { \ 1930 if (_isref) { /* only when _ctype==jobject */ \ 1931 Object* valObj = \ 1932 dvmDecodeIndirectRef(env, (jobject)(u4)value); \ 1933 dvmSetFieldObjectVolatile(obj, field->byteOffset, valObj); \ 1934 } else { \ 1935 dvmSetField##_jname##Volatile(obj, \ 1936 field->byteOffset, (_ctype2)value); \ 1937 } \ 1938 } else { \ 1939 if (_isref) { \ 1940 Object* valObj = \ 1941 dvmDecodeIndirectRef(env, (jobject)(u4)value); \ 1942 dvmSetFieldObject(obj, field->byteOffset, valObj); \ 1943 } else { \ 1944 dvmSetField##_jname(obj, \ 1945 field->byteOffset, (_ctype2)value); \ 1946 } \ 1947 } \ 1948 } 1949 SET_TYPE_FIELD(jobject, Object*, Object, true); 1950 SET_TYPE_FIELD(jboolean, bool, Boolean, false); 1951 SET_TYPE_FIELD(jbyte, s1, Byte, false); 1952 SET_TYPE_FIELD(jchar, u2, Char, false); 1953 SET_TYPE_FIELD(jshort, s2, Short, false); 1954 SET_TYPE_FIELD(jint, s4, Int, false); 1955 SET_TYPE_FIELD(jlong, s8, Long, false); 1956 SET_TYPE_FIELD(jfloat, float, Float, false); 1957 SET_TYPE_FIELD(jdouble, double, Double, false); 1958 1959 /* 1960 * Make a virtual method call. 1961 * 1962 * Three versions (..., va_list, jvalue[]) for each return type. If we're 1963 * returning an Object, we have to add it to the local references table. 1964 */ 1965 #define CALL_VIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \ 1966 static _ctype Call##_jname##Method(JNIEnv* env, jobject jobj, \ 1967 jmethodID methodID, ...) \ 1968 { \ 1969 ScopedJniThreadState ts(env); \ 1970 Object* obj = dvmDecodeIndirectRef(env, jobj); \ 1971 const Method* meth; \ 1972 va_list args; \ 1973 JValue result; \ 1974 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \ 1975 if (meth == NULL) { \ 1976 return _retfail; \ 1977 } \ 1978 va_start(args, methodID); \ 1979 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \ 1980 va_end(args); \ 1981 if (_isref && !dvmCheckException(ts.self())) \ 1982 result.l = (Object*)addLocalReference(env, result.l); \ 1983 return _retok; \ 1984 } \ 1985 static _ctype Call##_jname##MethodV(JNIEnv* env, jobject jobj, \ 1986 jmethodID methodID, va_list args) \ 1987 { \ 1988 ScopedJniThreadState ts(env); \ 1989 Object* obj = dvmDecodeIndirectRef(env, jobj); \ 1990 const Method* meth; \ 1991 JValue result; \ 1992 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \ 1993 if (meth == NULL) { \ 1994 return _retfail; \ 1995 } \ 1996 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \ 1997 if (_isref && !dvmCheckException(ts.self())) \ 1998 result.l = (Object*)addLocalReference(env, result.l); \ 1999 return _retok; \ 2000 } \ 2001 static _ctype Call##_jname##MethodA(JNIEnv* env, jobject jobj, \ 2002 jmethodID methodID, jvalue* args) \ 2003 { \ 2004 ScopedJniThreadState ts(env); \ 2005 Object* obj = dvmDecodeIndirectRef(env, jobj); \ 2006 const Method* meth; \ 2007 JValue result; \ 2008 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \ 2009 if (meth == NULL) { \ 2010 return _retfail; \ 2011 } \ 2012 dvmCallMethodA(ts.self(), meth, obj, true, &result, args); \ 2013 if (_isref && !dvmCheckException(ts.self())) \ 2014 result.l = (Object*)addLocalReference(env, result.l); \ 2015 return _retok; \ 2016 } 2017 CALL_VIRTUAL(jobject, Object, NULL, (jobject) result.l, true); 2018 CALL_VIRTUAL(jboolean, Boolean, 0, result.z, false); 2019 CALL_VIRTUAL(jbyte, Byte, 0, result.b, false); 2020 CALL_VIRTUAL(jchar, Char, 0, result.c, false); 2021 CALL_VIRTUAL(jshort, Short, 0, result.s, false); 2022 CALL_VIRTUAL(jint, Int, 0, result.i, false); 2023 CALL_VIRTUAL(jlong, Long, 0, result.j, false); 2024 CALL_VIRTUAL(jfloat, Float, 0.0f, result.f, false); 2025 CALL_VIRTUAL(jdouble, Double, 0.0, result.d, false); 2026 CALL_VIRTUAL(void, Void, , , false); 2027 2028 /* 2029 * Make a "non-virtual" method call. We're still calling a virtual method, 2030 * but this time we're not doing an indirection through the object's vtable. 2031 * The "clazz" parameter defines which implementation of a method we want. 2032 * 2033 * Three versions (..., va_list, jvalue[]) for each return type. 2034 */ 2035 #define CALL_NONVIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \ 2036 static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, jobject jobj, \ 2037 jclass jclazz, jmethodID methodID, ...) \ 2038 { \ 2039 ScopedJniThreadState ts(env); \ 2040 Object* obj = dvmDecodeIndirectRef(env, jobj); \ 2041 ClassObject* clazz = \ 2042 (ClassObject*) dvmDecodeIndirectRef(env, jclazz); \ 2043 const Method* meth; \ 2044 va_list args; \ 2045 JValue result; \ 2046 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \ 2047 if (meth == NULL) { \ 2048 return _retfail; \ 2049 } \ 2050 va_start(args, methodID); \ 2051 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \ 2052 if (_isref && !dvmCheckException(ts.self())) \ 2053 result.l = (Object*)addLocalReference(env, result.l); \ 2054 va_end(args); \ 2055 return _retok; \ 2056 } \ 2057 static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, jobject jobj,\ 2058 jclass jclazz, jmethodID methodID, va_list args) \ 2059 { \ 2060 ScopedJniThreadState ts(env); \ 2061 Object* obj = dvmDecodeIndirectRef(env, jobj); \ 2062 ClassObject* clazz = \ 2063 (ClassObject*) dvmDecodeIndirectRef(env, jclazz); \ 2064 const Method* meth; \ 2065 JValue result; \ 2066 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \ 2067 if (meth == NULL) { \ 2068 return _retfail; \ 2069 } \ 2070 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \ 2071 if (_isref && !dvmCheckException(ts.self())) \ 2072 result.l = (Object*)addLocalReference(env, result.l); \ 2073 return _retok; \ 2074 } \ 2075 static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, jobject jobj,\ 2076 jclass jclazz, jmethodID methodID, jvalue* args) \ 2077 { \ 2078 ScopedJniThreadState ts(env); \ 2079 Object* obj = dvmDecodeIndirectRef(env, jobj); \ 2080 ClassObject* clazz = \ 2081 (ClassObject*) dvmDecodeIndirectRef(env, jclazz); \ 2082 const Method* meth; \ 2083 JValue result; \ 2084 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \ 2085 if (meth == NULL) { \ 2086 return _retfail; \ 2087 } \ 2088 dvmCallMethodA(ts.self(), meth, obj, true, &result, args); \ 2089 if (_isref && !dvmCheckException(ts.self())) \ 2090 result.l = (Object*)addLocalReference(env, result.l); \ 2091 return _retok; \ 2092 } 2093 CALL_NONVIRTUAL(jobject, Object, NULL, (jobject) result.l, true); 2094 CALL_NONVIRTUAL(jboolean, Boolean, 0, result.z, false); 2095 CALL_NONVIRTUAL(jbyte, Byte, 0, result.b, false); 2096 CALL_NONVIRTUAL(jchar, Char, 0, result.c, false); 2097 CALL_NONVIRTUAL(jshort, Short, 0, result.s, false); 2098 CALL_NONVIRTUAL(jint, Int, 0, result.i, false); 2099 CALL_NONVIRTUAL(jlong, Long, 0, result.j, false); 2100 CALL_NONVIRTUAL(jfloat, Float, 0.0f, result.f, false); 2101 CALL_NONVIRTUAL(jdouble, Double, 0.0, result.d, false); 2102 CALL_NONVIRTUAL(void, Void, , , false); 2103 2104 2105 /* 2106 * Call a static method. 2107 */ 2108 #define CALL_STATIC(_ctype, _jname, _retfail, _retok, _isref) \ 2109 static _ctype CallStatic##_jname##Method(JNIEnv* env, jclass jclazz, \ 2110 jmethodID methodID, ...) \ 2111 { \ 2112 UNUSED_PARAMETER(jclazz); \ 2113 ScopedJniThreadState ts(env); \ 2114 JValue result; \ 2115 va_list args; \ 2116 va_start(args, methodID); \ 2117 dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\ 2118 va_end(args); \ 2119 if (_isref && !dvmCheckException(ts.self())) \ 2120 result.l = (Object*)addLocalReference(env, result.l); \ 2121 return _retok; \ 2122 } \ 2123 static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass jclazz, \ 2124 jmethodID methodID, va_list args) \ 2125 { \ 2126 UNUSED_PARAMETER(jclazz); \ 2127 ScopedJniThreadState ts(env); \ 2128 JValue result; \ 2129 dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\ 2130 if (_isref && !dvmCheckException(ts.self())) \ 2131 result.l = (Object*)addLocalReference(env, result.l); \ 2132 return _retok; \ 2133 } \ 2134 static _ctype CallStatic##_jname##MethodA(JNIEnv* env, jclass jclazz, \ 2135 jmethodID methodID, jvalue* args) \ 2136 { \ 2137 UNUSED_PARAMETER(jclazz); \ 2138 ScopedJniThreadState ts(env); \ 2139 JValue result; \ 2140 dvmCallMethodA(ts.self(), (Method*)methodID, NULL, true, &result, args);\ 2141 if (_isref && !dvmCheckException(ts.self())) \ 2142 result.l = (Object*)addLocalReference(env, result.l); \ 2143 return _retok; \ 2144 } 2145 CALL_STATIC(jobject, Object, NULL, (jobject) result.l, true); 2146 CALL_STATIC(jboolean, Boolean, 0, result.z, false); 2147 CALL_STATIC(jbyte, Byte, 0, result.b, false); 2148 CALL_STATIC(jchar, Char, 0, result.c, false); 2149 CALL_STATIC(jshort, Short, 0, result.s, false); 2150 CALL_STATIC(jint, Int, 0, result.i, false); 2151 CALL_STATIC(jlong, Long, 0, result.j, false); 2152 CALL_STATIC(jfloat, Float, 0.0f, result.f, false); 2153 CALL_STATIC(jdouble, Double, 0.0, result.d, false); 2154 CALL_STATIC(void, Void, , , false); 2155 2156 /* 2157 * Create a new String from Unicode data. 2158 * 2159 * If "len" is zero, we will return an empty string even if "unicodeChars" 2160 * is NULL. (The JNI spec is vague here.) 2161 */ 2162 static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) { 2163 ScopedJniThreadState ts(env); 2164 StringObject* jstr = dvmCreateStringFromUnicode(unicodeChars, len); 2165 if (jstr == NULL) { 2166 return NULL; 2167 } 2168 dvmReleaseTrackedAlloc((Object*) jstr, NULL); 2169 return (jstring) addLocalReference(env, (Object*) jstr); 2170 } 2171 2172 /* 2173 * Return the length of a String in Unicode character units. 2174 */ 2175 static jsize GetStringLength(JNIEnv* env, jstring jstr) { 2176 ScopedJniThreadState ts(env); 2177 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr); 2178 return strObj->length(); 2179 } 2180 2181 2182 /* 2183 * Get a string's character data. 2184 * 2185 * The result is guaranteed to be valid until ReleaseStringChars is 2186 * called, which means we have to pin it or return a copy. 2187 */ 2188 static const jchar* GetStringChars(JNIEnv* env, jstring jstr, jboolean* isCopy) { 2189 ScopedJniThreadState ts(env); 2190 2191 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr); 2192 ArrayObject* strChars = strObj->array(); 2193 2194 pinPrimitiveArray(strChars); 2195 2196 const u2* data = strObj->chars(); 2197 if (isCopy != NULL) { 2198 *isCopy = JNI_FALSE; 2199 } 2200 return (jchar*) data; 2201 } 2202 2203 /* 2204 * Release our grip on some characters from a string. 2205 */ 2206 static void ReleaseStringChars(JNIEnv* env, jstring jstr, const jchar* chars) { 2207 ScopedJniThreadState ts(env); 2208 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr); 2209 ArrayObject* strChars = strObj->array(); 2210 unpinPrimitiveArray(strChars); 2211 } 2212 2213 /* 2214 * Create a new java.lang.String object from chars in modified UTF-8 form. 2215 * 2216 * The spec doesn't say how to handle a NULL string. Popular desktop VMs 2217 * accept it and return a NULL pointer in response. 2218 */ 2219 static jstring NewStringUTF(JNIEnv* env, const char* bytes) { 2220 ScopedJniThreadState ts(env); 2221 if (bytes == NULL) { 2222 return NULL; 2223 } 2224 /* note newStr could come back NULL on OOM */ 2225 StringObject* newStr = dvmCreateStringFromCstr(bytes); 2226 jstring result = (jstring) addLocalReference(env, (Object*) newStr); 2227 dvmReleaseTrackedAlloc((Object*)newStr, NULL); 2228 return result; 2229 } 2230 2231 /* 2232 * Return the length in bytes of the modified UTF-8 form of the string. 2233 */ 2234 static jsize GetStringUTFLength(JNIEnv* env, jstring jstr) { 2235 ScopedJniThreadState ts(env); 2236 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr); 2237 if (strObj == NULL) { 2238 return 0; // Should we throw something or assert? 2239 } 2240 return strObj->utfLength(); 2241 } 2242 2243 /* 2244 * Convert "string" to modified UTF-8 and return a pointer. The returned 2245 * value must be released with ReleaseStringUTFChars. 2246 * 2247 * According to the JNI reference, "Returns a pointer to a UTF-8 string, 2248 * or NULL if the operation fails. Returns NULL if and only if an invocation 2249 * of this function has thrown an exception." 2250 * 2251 * The behavior here currently follows that of other open-source VMs, which 2252 * quietly return NULL if "string" is NULL. We should consider throwing an 2253 * NPE. (The CheckJNI code blows up if you try to pass in a NULL string, 2254 * which should catch this sort of thing during development.) Certain other 2255 * VMs will crash with a segmentation fault. 2256 */ 2257 static const char* GetStringUTFChars(JNIEnv* env, jstring jstr, jboolean* isCopy) { 2258 ScopedJniThreadState ts(env); 2259 if (jstr == NULL) { 2260 /* this shouldn't happen; throw NPE? */ 2261 return NULL; 2262 } 2263 if (isCopy != NULL) { 2264 *isCopy = JNI_TRUE; 2265 } 2266 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr); 2267 char* newStr = dvmCreateCstrFromString(strObj); 2268 if (newStr == NULL) { 2269 /* assume memory failure */ 2270 dvmThrowOutOfMemoryError("native heap string alloc failed"); 2271 } 2272 return newStr; 2273 } 2274 2275 /* 2276 * Release a string created by GetStringUTFChars(). 2277 */ 2278 static void ReleaseStringUTFChars(JNIEnv* env, jstring jstr, const char* utf) { 2279 ScopedJniThreadState ts(env); 2280 free((char*) utf); 2281 } 2282 2283 /* 2284 * Return the capacity of the array. 2285 */ 2286 static jsize GetArrayLength(JNIEnv* env, jarray jarr) { 2287 ScopedJniThreadState ts(env); 2288 ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); 2289 return arrObj->length; 2290 } 2291 2292 /* 2293 * Construct a new array that holds objects from class "elementClass". 2294 */ 2295 static jobjectArray NewObjectArray(JNIEnv* env, jsize length, 2296 jclass jelementClass, jobject jinitialElement) 2297 { 2298 ScopedJniThreadState ts(env); 2299 2300 if (jelementClass == NULL) { 2301 dvmThrowNullPointerException("JNI NewObjectArray elementClass == NULL"); 2302 return NULL; 2303 } 2304 2305 ClassObject* elemClassObj = (ClassObject*) dvmDecodeIndirectRef(env, jelementClass); 2306 ClassObject* arrayClass = dvmFindArrayClassForElement(elemClassObj); 2307 ArrayObject* newObj = dvmAllocArrayByClass(arrayClass, length, ALLOC_DEFAULT); 2308 if (newObj == NULL) { 2309 assert(dvmCheckException(ts.self())); 2310 return NULL; 2311 } 2312 jobjectArray newArray = (jobjectArray) addLocalReference(env, (Object*) newObj); 2313 dvmReleaseTrackedAlloc((Object*) newObj, NULL); 2314 2315 /* 2316 * Initialize the array. 2317 */ 2318 if (jinitialElement != NULL) { 2319 Object* initialElement = dvmDecodeIndirectRef(env, jinitialElement); 2320 Object** arrayData = (Object**) (void*) newObj->contents; 2321 for (jsize i = 0; i < length; ++i) { 2322 arrayData[i] = initialElement; 2323 } 2324 } 2325 2326 return newArray; 2327 } 2328 2329 static bool checkArrayElementBounds(ArrayObject* arrayObj, jsize index) { 2330 assert(arrayObj != NULL); 2331 if (index < 0 || index >= (int) arrayObj->length) { 2332 dvmThrowArrayIndexOutOfBoundsException(arrayObj->length, index); 2333 return false; 2334 } 2335 return true; 2336 } 2337 2338 /* 2339 * Get one element of an Object array. 2340 * 2341 * Add the object to the local references table in case the array goes away. 2342 */ 2343 static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index) { 2344 ScopedJniThreadState ts(env); 2345 2346 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); 2347 if (!checkArrayElementBounds(arrayObj, index)) { 2348 return NULL; 2349 } 2350 2351 Object* value = ((Object**) (void*) arrayObj->contents)[index]; 2352 return addLocalReference(env, value); 2353 } 2354 2355 /* 2356 * Set one element of an Object array. 2357 */ 2358 static void SetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index, jobject jobj) { 2359 ScopedJniThreadState ts(env); 2360 2361 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); 2362 if (!checkArrayElementBounds(arrayObj, index)) { 2363 return; 2364 } 2365 2366 //LOGV("JNI: set element %d in array %p to %p", index, array, value); 2367 2368 Object* obj = dvmDecodeIndirectRef(env, jobj); 2369 dvmSetObjectArrayElement(arrayObj, index, obj); 2370 } 2371 2372 /* 2373 * Create a new array of primitive elements. 2374 */ 2375 #define NEW_PRIMITIVE_ARRAY(_artype, _jname, _typechar) \ 2376 static _artype New##_jname##Array(JNIEnv* env, jsize length) { \ 2377 ScopedJniThreadState ts(env); \ 2378 ArrayObject* arrayObj = dvmAllocPrimitiveArray(_typechar, length, ALLOC_DEFAULT); \ 2379 if (arrayObj == NULL) { \ 2380 return NULL; \ 2381 } \ 2382 _artype result = (_artype) addLocalReference(env, (Object*) arrayObj); \ 2383 dvmReleaseTrackedAlloc((Object*) arrayObj, NULL); \ 2384 return result; \ 2385 } 2386 NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean, 'Z'); 2387 NEW_PRIMITIVE_ARRAY(jbyteArray, Byte, 'B'); 2388 NEW_PRIMITIVE_ARRAY(jcharArray, Char, 'C'); 2389 NEW_PRIMITIVE_ARRAY(jshortArray, Short, 'S'); 2390 NEW_PRIMITIVE_ARRAY(jintArray, Int, 'I'); 2391 NEW_PRIMITIVE_ARRAY(jlongArray, Long, 'J'); 2392 NEW_PRIMITIVE_ARRAY(jfloatArray, Float, 'F'); 2393 NEW_PRIMITIVE_ARRAY(jdoubleArray, Double, 'D'); 2394 2395 /* 2396 * Get a pointer to a C array of primitive elements from an array object 2397 * of the matching type. 2398 * 2399 * In a compacting GC, we either need to return a copy of the elements or 2400 * "pin" the memory. Otherwise we run the risk of native code using the 2401 * buffer as the destination of e.g. a blocking read() call that wakes up 2402 * during a GC. 2403 */ 2404 #define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \ 2405 static _ctype* Get##_jname##ArrayElements(JNIEnv* env, \ 2406 _ctype##Array jarr, jboolean* isCopy) \ 2407 { \ 2408 ScopedJniThreadState ts(env); \ 2409 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \ 2410 pinPrimitiveArray(arrayObj); \ 2411 _ctype* data = (_ctype*) (void*) arrayObj->contents; \ 2412 if (isCopy != NULL) { \ 2413 *isCopy = JNI_FALSE; \ 2414 } \ 2415 return data; \ 2416 } 2417 2418 /* 2419 * Release the storage locked down by the "get" function. 2420 * 2421 * The spec says, "'mode' has no effect if 'elems' is not a copy of the 2422 * elements in 'array'." They apparently did not anticipate the need to 2423 * un-pin memory. 2424 */ 2425 #define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \ 2426 static void Release##_jname##ArrayElements(JNIEnv* env, \ 2427 _ctype##Array jarr, _ctype* elems, jint mode) \ 2428 { \ 2429 UNUSED_PARAMETER(elems); \ 2430 if (mode != JNI_COMMIT) { \ 2431 ScopedJniThreadState ts(env); \ 2432 ArrayObject* arrayObj = \ 2433 (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \ 2434 unpinPrimitiveArray(arrayObj); \ 2435 } \ 2436 } 2437 2438 static void throwArrayRegionOutOfBounds(ArrayObject* arrayObj, jsize start, 2439 jsize len, const char* arrayIdentifier) 2440 { 2441 dvmThrowExceptionFmt(gDvm.exArrayIndexOutOfBoundsException, 2442 "%s offset=%d length=%d %s.length=%d", 2443 arrayObj->clazz->descriptor, start, len, arrayIdentifier, 2444 arrayObj->length); 2445 } 2446 2447 /* 2448 * Copy a section of a primitive array to a buffer. 2449 */ 2450 #define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \ 2451 static void Get##_jname##ArrayRegion(JNIEnv* env, \ 2452 _ctype##Array jarr, jsize start, jsize len, _ctype* buf) \ 2453 { \ 2454 ScopedJniThreadState ts(env); \ 2455 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \ 2456 _ctype* data = (_ctype*) (void*) arrayObj->contents; \ 2457 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \ 2458 throwArrayRegionOutOfBounds(arrayObj, start, len, "src"); \ 2459 } else { \ 2460 memcpy(buf, data + start, len * sizeof(_ctype)); \ 2461 } \ 2462 } 2463 2464 /* 2465 * Copy a section of a primitive array from a buffer. 2466 */ 2467 #define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \ 2468 static void Set##_jname##ArrayRegion(JNIEnv* env, \ 2469 _ctype##Array jarr, jsize start, jsize len, const _ctype* buf) \ 2470 { \ 2471 ScopedJniThreadState ts(env); \ 2472 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); \ 2473 _ctype* data = (_ctype*) (void*) arrayObj->contents; \ 2474 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \ 2475 throwArrayRegionOutOfBounds(arrayObj, start, len, "dst"); \ 2476 } else { \ 2477 memcpy(data + start, buf, len * sizeof(_ctype)); \ 2478 } \ 2479 } 2480 2481 /* 2482 * 4-in-1: 2483 * Get<Type>ArrayElements 2484 * Release<Type>ArrayElements 2485 * Get<Type>ArrayRegion 2486 * Set<Type>ArrayRegion 2487 */ 2488 #define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname) \ 2489 GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \ 2490 RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \ 2491 GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \ 2492 SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); 2493 2494 PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean); 2495 PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte); 2496 PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char); 2497 PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short); 2498 PRIMITIVE_ARRAY_FUNCTIONS(jint, Int); 2499 PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long); 2500 PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float); 2501 PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double); 2502 2503 /* 2504 * Register one or more native functions in one class. 2505 * 2506 * This can be called multiple times on the same method, allowing the 2507 * caller to redefine the method implementation at will. 2508 */ 2509 static jint RegisterNatives(JNIEnv* env, jclass jclazz, 2510 const JNINativeMethod* methods, jint nMethods) 2511 { 2512 ScopedJniThreadState ts(env); 2513 2514 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 2515 2516 if (gDvm.verboseJni) { 2517 LOGI("[Registering JNI native methods for class %s]", 2518 clazz->descriptor); 2519 } 2520 2521 for (int i = 0; i < nMethods; i++) { 2522 if (!dvmRegisterJNIMethod(clazz, methods[i].name, 2523 methods[i].signature, methods[i].fnPtr)) 2524 { 2525 return JNI_ERR; 2526 } 2527 } 2528 return JNI_OK; 2529 } 2530 2531 /* 2532 * Un-register all native methods associated with the class. 2533 * 2534 * The JNI docs refer to this as a way to reload/relink native libraries, 2535 * and say it "should not be used in normal native code". In particular, 2536 * there is no need to do this during shutdown, and you do not need to do 2537 * this before redefining a method implementation with RegisterNatives. 2538 * 2539 * It's chiefly useful for a native "plugin"-style library that wasn't 2540 * loaded with System.loadLibrary() (since there's no way to unload those). 2541 * For example, the library could upgrade itself by: 2542 * 2543 * 1. call UnregisterNatives to unbind the old methods 2544 * 2. ensure that no code is still executing inside it (somehow) 2545 * 3. dlclose() the library 2546 * 4. dlopen() the new library 2547 * 5. use RegisterNatives to bind the methods from the new library 2548 * 2549 * The above can work correctly without the UnregisterNatives call, but 2550 * creates a window of opportunity in which somebody might try to call a 2551 * method that is pointing at unmapped memory, crashing the VM. In theory 2552 * the same guards that prevent dlclose() from unmapping executing code could 2553 * prevent that anyway, but with this we can be more thorough and also deal 2554 * with methods that only exist in the old or new form of the library (maybe 2555 * the lib wants to try the call and catch the UnsatisfiedLinkError). 2556 */ 2557 static jint UnregisterNatives(JNIEnv* env, jclass jclazz) { 2558 ScopedJniThreadState ts(env); 2559 2560 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz); 2561 if (gDvm.verboseJni) { 2562 LOGI("[Unregistering JNI native methods for class %s]", 2563 clazz->descriptor); 2564 } 2565 dvmUnregisterJNINativeMethods(clazz); 2566 return JNI_OK; 2567 } 2568 2569 /* 2570 * Lock the monitor. 2571 * 2572 * We have to track all monitor enters and exits, so that we can undo any 2573 * outstanding synchronization before the thread exits. 2574 */ 2575 static jint MonitorEnter(JNIEnv* env, jobject jobj) { 2576 ScopedJniThreadState ts(env); 2577 Object* obj = dvmDecodeIndirectRef(env, jobj); 2578 dvmLockObject(ts.self(), obj); 2579 trackMonitorEnter(ts.self(), obj); 2580 return JNI_OK; 2581 } 2582 2583 /* 2584 * Unlock the monitor. 2585 * 2586 * Throws an IllegalMonitorStateException if the current thread 2587 * doesn't own the monitor. (dvmUnlockObject() takes care of the throw.) 2588 * 2589 * According to the 1.6 spec, it's legal to call here with an exception 2590 * pending. If this fails, we'll stomp the original exception. 2591 */ 2592 static jint MonitorExit(JNIEnv* env, jobject jobj) { 2593 ScopedJniThreadState ts(env); 2594 Object* obj = dvmDecodeIndirectRef(env, jobj); 2595 bool success = dvmUnlockObject(ts.self(), obj); 2596 if (success) { 2597 trackMonitorExit(ts.self(), obj); 2598 } 2599 return success ? JNI_OK : JNI_ERR; 2600 } 2601 2602 /* 2603 * Return the JavaVM interface associated with the current thread. 2604 */ 2605 static jint GetJavaVM(JNIEnv* env, JavaVM** vm) { 2606 ScopedJniThreadState ts(env); 2607 *vm = gDvmJni.jniVm; 2608 return (*vm == NULL) ? JNI_ERR : JNI_OK; 2609 } 2610 2611 /* 2612 * Copies "len" Unicode characters, from offset "start". 2613 */ 2614 static void GetStringRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, jchar* buf) { 2615 ScopedJniThreadState ts(env); 2616 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr); 2617 int strLen = strObj->length(); 2618 if (((start|len) < 0) || (start + len > strLen)) { 2619 dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len); 2620 return; 2621 } 2622 memcpy(buf, strObj->chars() + start, len * sizeof(u2)); 2623 } 2624 2625 /* 2626 * Translates "len" Unicode characters, from offset "start", into 2627 * modified UTF-8 encoding. 2628 */ 2629 static void GetStringUTFRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, char* buf) { 2630 ScopedJniThreadState ts(env); 2631 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr); 2632 int strLen = strObj->length(); 2633 if (((start|len) < 0) || (start + len > strLen)) { 2634 dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len); 2635 return; 2636 } 2637 dvmGetStringUtfRegion(strObj, start, len, buf); 2638 } 2639 2640 /* 2641 * Get a raw pointer to array data. 2642 * 2643 * The caller is expected to call "release" before doing any JNI calls 2644 * or blocking I/O operations. 2645 * 2646 * We need to pin the memory or block GC. 2647 */ 2648 static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray jarr, jboolean* isCopy) { 2649 ScopedJniThreadState ts(env); 2650 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); 2651 pinPrimitiveArray(arrayObj); 2652 void* data = arrayObj->contents; 2653 if (isCopy != NULL) { 2654 *isCopy = JNI_FALSE; 2655 } 2656 return data; 2657 } 2658 2659 /* 2660 * Release an array obtained with GetPrimitiveArrayCritical. 2661 */ 2662 static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray jarr, void* carray, jint mode) { 2663 if (mode != JNI_COMMIT) { 2664 ScopedJniThreadState ts(env); 2665 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr); 2666 unpinPrimitiveArray(arrayObj); 2667 } 2668 } 2669 2670 /* 2671 * Like GetStringChars, but with restricted use. 2672 */ 2673 static const jchar* GetStringCritical(JNIEnv* env, jstring jstr, jboolean* isCopy) { 2674 ScopedJniThreadState ts(env); 2675 2676 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr); 2677 ArrayObject* strChars = strObj->array(); 2678 2679 pinPrimitiveArray(strChars); 2680 2681 const u2* data = strObj->chars(); 2682 if (isCopy != NULL) { 2683 *isCopy = JNI_FALSE; 2684 } 2685 return (jchar*) data; 2686 } 2687 2688 /* 2689 * Like ReleaseStringChars, but with restricted use. 2690 */ 2691 static void ReleaseStringCritical(JNIEnv* env, jstring jstr, const jchar* carray) { 2692 ScopedJniThreadState ts(env); 2693 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, jstr); 2694 ArrayObject* strChars = strObj->array(); 2695 unpinPrimitiveArray(strChars); 2696 } 2697 2698 /* 2699 * Create a new weak global reference. 2700 */ 2701 static jweak NewWeakGlobalRef(JNIEnv* env, jobject jobj) { 2702 ScopedJniThreadState ts(env); 2703 Object *obj = dvmDecodeIndirectRef(env, jobj); 2704 return (jweak) addWeakGlobalReference(obj); 2705 } 2706 2707 /* 2708 * Delete the specified weak global reference. 2709 */ 2710 static void DeleteWeakGlobalRef(JNIEnv* env, jweak wref) { 2711 ScopedJniThreadState ts(env); 2712 deleteWeakGlobalReference(wref); 2713 } 2714 2715 /* 2716 * Quick check for pending exceptions. 2717 * 2718 * TODO: we should be able to skip the enter/exit macros here. 2719 */ 2720 static jboolean ExceptionCheck(JNIEnv* env) { 2721 ScopedJniThreadState ts(env); 2722 return dvmCheckException(ts.self()); 2723 } 2724 2725 /* 2726 * Returns the type of the object referred to by "obj". It can be local, 2727 * global, or weak global. 2728 * 2729 * In the current implementation, references can be global and local at 2730 * the same time, so while the return value is accurate it may not tell 2731 * the whole story. 2732 */ 2733 static jobjectRefType GetObjectRefType(JNIEnv* env, jobject jobj) { 2734 ScopedJniThreadState ts(env); 2735 return dvmGetJNIRefType(env, jobj); 2736 } 2737 2738 /* 2739 * Allocate and return a new java.nio.ByteBuffer for this block of memory. 2740 * 2741 * "address" may not be NULL, and "capacity" must be > 0. (These are only 2742 * verified when CheckJNI is enabled.) 2743 */ 2744 static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) { 2745 ScopedJniThreadState ts(env); 2746 2747 /* create an instance of java.nio.ReadWriteDirectByteBuffer */ 2748 ClassObject* bufferClazz = gDvm.classJavaNioReadWriteDirectByteBuffer; 2749 if (!dvmIsClassInitialized(bufferClazz) && !dvmInitClass(bufferClazz)) { 2750 return NULL; 2751 } 2752 Object* newObj = dvmAllocObject(bufferClazz, ALLOC_DONT_TRACK); 2753 if (newObj == NULL) { 2754 return NULL; 2755 } 2756 /* call the constructor */ 2757 jobject result = addLocalReference(env, newObj); 2758 JValue unused; 2759 dvmCallMethod(ts.self(), gDvm.methJavaNioReadWriteDirectByteBuffer_init, 2760 newObj, &unused, (jint) address, (jint) capacity); 2761 if (dvmGetException(ts.self()) != NULL) { 2762 deleteLocalReference(env, result); 2763 return NULL; 2764 } 2765 return result; 2766 } 2767 2768 /* 2769 * Get the starting address of the buffer for the specified java.nio.Buffer. 2770 * 2771 * If this is not a "direct" buffer, we return NULL. 2772 */ 2773 static void* GetDirectBufferAddress(JNIEnv* env, jobject jbuf) { 2774 ScopedJniThreadState ts(env); 2775 2776 // All Buffer objects have an effectiveDirectAddress field. 2777 Object* bufObj = dvmDecodeIndirectRef(env, jbuf); 2778 return (void*) dvmGetFieldInt(bufObj, gDvm.offJavaNioBuffer_effectiveDirectAddress); 2779 } 2780 2781 /* 2782 * Get the capacity of the buffer for the specified java.nio.Buffer. 2783 * 2784 * Returns -1 if the object is not a direct buffer. (We actually skip 2785 * this check, since it's expensive to determine, and just return the 2786 * capacity regardless.) 2787 */ 2788 static jlong GetDirectBufferCapacity(JNIEnv* env, jobject jbuf) { 2789 ScopedJniThreadState ts(env); 2790 2791 /* 2792 * The capacity is always in the Buffer.capacity field. 2793 * 2794 * (The "check" version should verify that this is actually a Buffer, 2795 * but we're not required to do so here.) 2796 */ 2797 Object* buf = dvmDecodeIndirectRef(env, jbuf); 2798 return dvmGetFieldInt(buf, gDvm.offJavaNioBuffer_capacity); 2799 } 2800 2801 2802 /* 2803 * =========================================================================== 2804 * JNI invocation functions 2805 * =========================================================================== 2806 */ 2807 2808 /* 2809 * Handle AttachCurrentThread{AsDaemon}. 2810 * 2811 * We need to make sure the VM is actually running. For example, if we start 2812 * up, issue an Attach, and the VM exits almost immediately, by the time the 2813 * attaching happens the VM could already be shutting down. 2814 * 2815 * It's hard to avoid a race condition here because we don't want to hold 2816 * a lock across the entire operation. What we can do is temporarily 2817 * increment the thread count to prevent a VM exit. 2818 * 2819 * This could potentially still have problems if a daemon thread calls here 2820 * while the VM is shutting down. dvmThreadSelf() will work, since it just 2821 * uses pthread TLS, but dereferencing "vm" could fail. Such is life when 2822 * you shut down a VM while threads are still running inside it. 2823 * 2824 * Remember that some code may call this as a way to find the per-thread 2825 * JNIEnv pointer. Don't do excess work for that case. 2826 */ 2827 static jint attachThread(JavaVM* vm, JNIEnv** p_env, void* thr_args, bool isDaemon) { 2828 JavaVMAttachArgs* args = (JavaVMAttachArgs*) thr_args; 2829 2830 /* 2831 * Return immediately if we're already one with the VM. 2832 */ 2833 Thread* self = dvmThreadSelf(); 2834 if (self != NULL) { 2835 *p_env = self->jniEnv; 2836 return JNI_OK; 2837 } 2838 2839 /* 2840 * No threads allowed in zygote mode. 2841 */ 2842 if (gDvm.zygote) { 2843 return JNI_ERR; 2844 } 2845 2846 /* increment the count to keep the VM from bailing while we run */ 2847 dvmLockThreadList(NULL); 2848 if (gDvm.nonDaemonThreadCount == 0) { 2849 // dead or dying 2850 LOGV("Refusing to attach thread '%s' -- VM is shutting down", 2851 (thr_args == NULL) ? "(unknown)" : args->name); 2852 dvmUnlockThreadList(); 2853 return JNI_ERR; 2854 } 2855 gDvm.nonDaemonThreadCount++; 2856 dvmUnlockThreadList(); 2857 2858 /* tweak the JavaVMAttachArgs as needed */ 2859 JavaVMAttachArgs argsCopy; 2860 if (args == NULL) { 2861 /* allow the v1.1 calling convention */ 2862 argsCopy.version = JNI_VERSION_1_2; 2863 argsCopy.name = NULL; 2864 argsCopy.group = (jobject) dvmGetMainThreadGroup(); 2865 } else { 2866 assert(args->version >= JNI_VERSION_1_2); 2867 2868 argsCopy.version = args->version; 2869 argsCopy.name = args->name; 2870 if (args->group != NULL) { 2871 argsCopy.group = (jobject) dvmDecodeIndirectRef(NULL, args->group); 2872 } else { 2873 argsCopy.group = (jobject) dvmGetMainThreadGroup(); 2874 } 2875 } 2876 2877 bool result = dvmAttachCurrentThread(&argsCopy, isDaemon); 2878 2879 /* restore the count */ 2880 dvmLockThreadList(NULL); 2881 gDvm.nonDaemonThreadCount--; 2882 dvmUnlockThreadList(); 2883 2884 /* 2885 * Change the status to indicate that we're out in native code. This 2886 * call is not guarded with state-change macros, so we have to do it 2887 * by hand. 2888 */ 2889 if (result) { 2890 self = dvmThreadSelf(); 2891 assert(self != NULL); 2892 dvmChangeStatus(self, THREAD_NATIVE); 2893 *p_env = self->jniEnv; 2894 return JNI_OK; 2895 } else { 2896 return JNI_ERR; 2897 } 2898 } 2899 2900 /* 2901 * Attach the current thread to the VM. If the thread is already attached, 2902 * this is a no-op. 2903 */ 2904 static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) { 2905 return attachThread(vm, p_env, thr_args, false); 2906 } 2907 2908 /* 2909 * Like AttachCurrentThread, but set the "daemon" flag. 2910 */ 2911 static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args) 2912 { 2913 return attachThread(vm, p_env, thr_args, true); 2914 } 2915 2916 /* 2917 * Dissociate the current thread from the VM. 2918 */ 2919 static jint DetachCurrentThread(JavaVM* vm) { 2920 Thread* self = dvmThreadSelf(); 2921 if (self == NULL) { 2922 /* not attached, can't do anything */ 2923 return JNI_ERR; 2924 } 2925 2926 /* switch to "running" to check for suspension */ 2927 dvmChangeStatus(self, THREAD_RUNNING); 2928 2929 /* detach the thread */ 2930 dvmDetachCurrentThread(); 2931 2932 /* (no need to change status back -- we have no status) */ 2933 return JNI_OK; 2934 } 2935 2936 /* 2937 * If current thread is attached to VM, return the associated JNIEnv. 2938 * Otherwise, stuff NULL in and return JNI_EDETACHED. 2939 * 2940 * JVMTI overloads this by specifying a magic value for "version", so we 2941 * do want to check that here. 2942 */ 2943 static jint GetEnv(JavaVM* vm, void** env, jint version) { 2944 Thread* self = dvmThreadSelf(); 2945 2946 if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6) { 2947 return JNI_EVERSION; 2948 } 2949 2950 if (self == NULL) { 2951 *env = NULL; 2952 } else { 2953 /* TODO: status change is probably unnecessary */ 2954 dvmChangeStatus(self, THREAD_RUNNING); 2955 *env = (void*) dvmGetThreadJNIEnv(self); 2956 dvmChangeStatus(self, THREAD_NATIVE); 2957 } 2958 return (*env != NULL) ? JNI_OK : JNI_EDETACHED; 2959 } 2960 2961 /* 2962 * Destroy the VM. This may be called from any thread. 2963 * 2964 * If the current thread is attached, wait until the current thread is 2965 * the only non-daemon user-level thread. If the current thread is not 2966 * attached, we attach it and do the processing as usual. (If the attach 2967 * fails, it's probably because all the non-daemon threads have already 2968 * exited and the VM doesn't want to let us back in.) 2969 * 2970 * TODO: we don't really deal with the situation where more than one thread 2971 * has called here. One thread wins, the other stays trapped waiting on 2972 * the condition variable forever. Not sure this situation is interesting 2973 * in real life. 2974 */ 2975 static jint DestroyJavaVM(JavaVM* vm) { 2976 JavaVMExt* ext = (JavaVMExt*) vm; 2977 if (ext == NULL) { 2978 return JNI_ERR; 2979 } 2980 2981 if (gDvm.verboseShutdown) { 2982 LOGD("DestroyJavaVM waiting for non-daemon threads to exit"); 2983 } 2984 2985 /* 2986 * Sleep on a condition variable until it's okay to exit. 2987 */ 2988 Thread* self = dvmThreadSelf(); 2989 if (self == NULL) { 2990 JNIEnv* tmpEnv; 2991 if (AttachCurrentThread(vm, &tmpEnv, NULL) != JNI_OK) { 2992 LOGV("Unable to reattach main for Destroy; assuming VM is shutting down (count=%d)", 2993 gDvm.nonDaemonThreadCount); 2994 goto shutdown; 2995 } else { 2996 LOGV("Attached to wait for shutdown in Destroy"); 2997 } 2998 } 2999 dvmChangeStatus(self, THREAD_VMWAIT); 3000 3001 dvmLockThreadList(self); 3002 gDvm.nonDaemonThreadCount--; // remove current thread from count 3003 3004 while (gDvm.nonDaemonThreadCount > 0) { 3005 pthread_cond_wait(&gDvm.vmExitCond, &gDvm.threadListLock); 3006 } 3007 3008 dvmUnlockThreadList(); 3009 self = NULL; 3010 3011 shutdown: 3012 // TODO: call System.exit() to run any registered shutdown hooks 3013 // (this may not return -- figure out how this should work) 3014 3015 if (gDvm.verboseShutdown) { 3016 LOGD("DestroyJavaVM shutting VM down"); 3017 } 3018 dvmShutdown(); 3019 3020 // TODO - free resources associated with JNI-attached daemon threads 3021 free(ext->envList); 3022 free(ext); 3023 3024 return JNI_OK; 3025 } 3026 3027 3028 /* 3029 * =========================================================================== 3030 * Function tables 3031 * =========================================================================== 3032 */ 3033 3034 static const struct JNINativeInterface gNativeInterface = { 3035 NULL, 3036 NULL, 3037 NULL, 3038 NULL, 3039 3040 GetVersion, 3041 3042 DefineClass, 3043 FindClass, 3044 3045 FromReflectedMethod, 3046 FromReflectedField, 3047 ToReflectedMethod, 3048 3049 GetSuperclass, 3050 IsAssignableFrom, 3051 3052 ToReflectedField, 3053 3054 Throw, 3055 ThrowNew, 3056 ExceptionOccurred, 3057 ExceptionDescribe, 3058 ExceptionClear, 3059 FatalError, 3060 3061 PushLocalFrame, 3062 PopLocalFrame, 3063 3064 NewGlobalRef, 3065 DeleteGlobalRef, 3066 DeleteLocalRef, 3067 IsSameObject, 3068 NewLocalRef, 3069 EnsureLocalCapacity, 3070 3071 AllocObject, 3072 NewObject, 3073 NewObjectV, 3074 NewObjectA, 3075 3076 GetObjectClass, 3077 IsInstanceOf, 3078 3079 GetMethodID, 3080 3081 CallObjectMethod, 3082 CallObjectMethodV, 3083 CallObjectMethodA, 3084 CallBooleanMethod, 3085 CallBooleanMethodV, 3086 CallBooleanMethodA, 3087 CallByteMethod, 3088 CallByteMethodV, 3089 CallByteMethodA, 3090 CallCharMethod, 3091 CallCharMethodV, 3092 CallCharMethodA, 3093 CallShortMethod, 3094 CallShortMethodV, 3095 CallShortMethodA, 3096 CallIntMethod, 3097 CallIntMethodV, 3098 CallIntMethodA, 3099 CallLongMethod, 3100 CallLongMethodV, 3101 CallLongMethodA, 3102 CallFloatMethod, 3103 CallFloatMethodV, 3104 CallFloatMethodA, 3105 CallDoubleMethod, 3106 CallDoubleMethodV, 3107 CallDoubleMethodA, 3108 CallVoidMethod, 3109 CallVoidMethodV, 3110 CallVoidMethodA, 3111 3112 CallNonvirtualObjectMethod, 3113 CallNonvirtualObjectMethodV, 3114 CallNonvirtualObjectMethodA, 3115 CallNonvirtualBooleanMethod, 3116 CallNonvirtualBooleanMethodV, 3117 CallNonvirtualBooleanMethodA, 3118 CallNonvirtualByteMethod, 3119 CallNonvirtualByteMethodV, 3120 CallNonvirtualByteMethodA, 3121 CallNonvirtualCharMethod, 3122 CallNonvirtualCharMethodV, 3123 CallNonvirtualCharMethodA, 3124 CallNonvirtualShortMethod, 3125 CallNonvirtualShortMethodV, 3126 CallNonvirtualShortMethodA, 3127 CallNonvirtualIntMethod, 3128 CallNonvirtualIntMethodV, 3129 CallNonvirtualIntMethodA, 3130 CallNonvirtualLongMethod, 3131 CallNonvirtualLongMethodV, 3132 CallNonvirtualLongMethodA, 3133 CallNonvirtualFloatMethod, 3134 CallNonvirtualFloatMethodV, 3135 CallNonvirtualFloatMethodA, 3136 CallNonvirtualDoubleMethod, 3137 CallNonvirtualDoubleMethodV, 3138 CallNonvirtualDoubleMethodA, 3139 CallNonvirtualVoidMethod, 3140 CallNonvirtualVoidMethodV, 3141 CallNonvirtualVoidMethodA, 3142 3143 GetFieldID, 3144 3145 GetObjectField, 3146 GetBooleanField, 3147 GetByteField, 3148 GetCharField, 3149 GetShortField, 3150 GetIntField, 3151 GetLongField, 3152 GetFloatField, 3153 GetDoubleField, 3154 SetObjectField, 3155 SetBooleanField, 3156 SetByteField, 3157 SetCharField, 3158 SetShortField, 3159 SetIntField, 3160 SetLongField, 3161 SetFloatField, 3162 SetDoubleField, 3163 3164 GetStaticMethodID, 3165 3166 CallStaticObjectMethod, 3167 CallStaticObjectMethodV, 3168 CallStaticObjectMethodA, 3169 CallStaticBooleanMethod, 3170 CallStaticBooleanMethodV, 3171 CallStaticBooleanMethodA, 3172 CallStaticByteMethod, 3173 CallStaticByteMethodV, 3174 CallStaticByteMethodA, 3175 CallStaticCharMethod, 3176 CallStaticCharMethodV, 3177 CallStaticCharMethodA, 3178 CallStaticShortMethod, 3179 CallStaticShortMethodV, 3180 CallStaticShortMethodA, 3181 CallStaticIntMethod, 3182 CallStaticIntMethodV, 3183 CallStaticIntMethodA, 3184 CallStaticLongMethod, 3185 CallStaticLongMethodV, 3186 CallStaticLongMethodA, 3187 CallStaticFloatMethod, 3188 CallStaticFloatMethodV, 3189 CallStaticFloatMethodA, 3190 CallStaticDoubleMethod, 3191 CallStaticDoubleMethodV, 3192 CallStaticDoubleMethodA, 3193 CallStaticVoidMethod, 3194 CallStaticVoidMethodV, 3195 CallStaticVoidMethodA, 3196 3197 GetStaticFieldID, 3198 3199 GetStaticObjectField, 3200 GetStaticBooleanField, 3201 GetStaticByteField, 3202 GetStaticCharField, 3203 GetStaticShortField, 3204 GetStaticIntField, 3205 GetStaticLongField, 3206 GetStaticFloatField, 3207 GetStaticDoubleField, 3208 3209 SetStaticObjectField, 3210 SetStaticBooleanField, 3211 SetStaticByteField, 3212 SetStaticCharField, 3213 SetStaticShortField, 3214 SetStaticIntField, 3215 SetStaticLongField, 3216 SetStaticFloatField, 3217 SetStaticDoubleField, 3218 3219 NewString, 3220 3221 GetStringLength, 3222 GetStringChars, 3223 ReleaseStringChars, 3224 3225 NewStringUTF, 3226 GetStringUTFLength, 3227 GetStringUTFChars, 3228 ReleaseStringUTFChars, 3229 3230 GetArrayLength, 3231 NewObjectArray, 3232 GetObjectArrayElement, 3233 SetObjectArrayElement, 3234 3235 NewBooleanArray, 3236 NewByteArray, 3237 NewCharArray, 3238 NewShortArray, 3239 NewIntArray, 3240 NewLongArray, 3241 NewFloatArray, 3242 NewDoubleArray, 3243 3244 GetBooleanArrayElements, 3245 GetByteArrayElements, 3246 GetCharArrayElements, 3247 GetShortArrayElements, 3248 GetIntArrayElements, 3249 GetLongArrayElements, 3250 GetFloatArrayElements, 3251 GetDoubleArrayElements, 3252 3253 ReleaseBooleanArrayElements, 3254 ReleaseByteArrayElements, 3255 ReleaseCharArrayElements, 3256 ReleaseShortArrayElements, 3257 ReleaseIntArrayElements, 3258 ReleaseLongArrayElements, 3259 ReleaseFloatArrayElements, 3260 ReleaseDoubleArrayElements, 3261 3262 GetBooleanArrayRegion, 3263 GetByteArrayRegion, 3264 GetCharArrayRegion, 3265 GetShortArrayRegion, 3266 GetIntArrayRegion, 3267 GetLongArrayRegion, 3268 GetFloatArrayRegion, 3269 GetDoubleArrayRegion, 3270 SetBooleanArrayRegion, 3271 SetByteArrayRegion, 3272 SetCharArrayRegion, 3273 SetShortArrayRegion, 3274 SetIntArrayRegion, 3275 SetLongArrayRegion, 3276 SetFloatArrayRegion, 3277 SetDoubleArrayRegion, 3278 3279 RegisterNatives, 3280 UnregisterNatives, 3281 3282 MonitorEnter, 3283 MonitorExit, 3284 3285 GetJavaVM, 3286 3287 GetStringRegion, 3288 GetStringUTFRegion, 3289 3290 GetPrimitiveArrayCritical, 3291 ReleasePrimitiveArrayCritical, 3292 3293 GetStringCritical, 3294 ReleaseStringCritical, 3295 3296 NewWeakGlobalRef, 3297 DeleteWeakGlobalRef, 3298 3299 ExceptionCheck, 3300 3301 NewDirectByteBuffer, 3302 GetDirectBufferAddress, 3303 GetDirectBufferCapacity, 3304 3305 GetObjectRefType 3306 }; 3307 3308 static const struct JNIInvokeInterface gInvokeInterface = { 3309 NULL, 3310 NULL, 3311 NULL, 3312 3313 DestroyJavaVM, 3314 AttachCurrentThread, 3315 DetachCurrentThread, 3316 3317 GetEnv, 3318 3319 AttachCurrentThreadAsDaemon, 3320 }; 3321 3322 /* 3323 * =========================================================================== 3324 * VM/Env creation 3325 * =========================================================================== 3326 */ 3327 3328 /* 3329 * Create a new JNIEnv struct and add it to the VM's list. 3330 * 3331 * "self" will be NULL for the main thread, since the VM hasn't started 3332 * yet; the value will be filled in later. 3333 */ 3334 JNIEnv* dvmCreateJNIEnv(Thread* self) { 3335 JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm; 3336 3337 //if (self != NULL) 3338 // LOGI("Ent CreateJNIEnv: threadid=%d %p", self->threadId, self); 3339 3340 assert(vm != NULL); 3341 3342 JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt)); 3343 newEnv->funcTable = &gNativeInterface; 3344 if (self != NULL) { 3345 dvmSetJniEnvThreadId((JNIEnv*) newEnv, self); 3346 assert(newEnv->envThreadId != 0); 3347 } else { 3348 /* make it obvious if we fail to initialize these later */ 3349 newEnv->envThreadId = 0x77777775; 3350 newEnv->self = (Thread*) 0x77777779; 3351 } 3352 if (gDvmJni.useCheckJni) { 3353 dvmUseCheckedJniEnv(newEnv); 3354 } 3355 3356 ScopedPthreadMutexLock lock(&vm->envListLock); 3357 3358 /* insert at head of list */ 3359 newEnv->next = vm->envList; 3360 assert(newEnv->prev == NULL); 3361 if (vm->envList == NULL) { 3362 // rare, but possible 3363 vm->envList = newEnv; 3364 } else { 3365 vm->envList->prev = newEnv; 3366 } 3367 vm->envList = newEnv; 3368 3369 //if (self != NULL) 3370 // LOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self); 3371 return (JNIEnv*) newEnv; 3372 } 3373 3374 /* 3375 * Remove a JNIEnv struct from the list and free it. 3376 */ 3377 void dvmDestroyJNIEnv(JNIEnv* env) { 3378 if (env == NULL) { 3379 return; 3380 } 3381 3382 //LOGI("Ent DestroyJNIEnv: threadid=%d %p", self->threadId, self); 3383 3384 JNIEnvExt* extEnv = (JNIEnvExt*) env; 3385 JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm; 3386 3387 ScopedPthreadMutexLock lock(&vm->envListLock); 3388 3389 if (extEnv == vm->envList) { 3390 assert(extEnv->prev == NULL); 3391 vm->envList = extEnv->next; 3392 } else { 3393 assert(extEnv->prev != NULL); 3394 extEnv->prev->next = extEnv->next; 3395 } 3396 if (extEnv->next != NULL) { 3397 extEnv->next->prev = extEnv->prev; 3398 } 3399 3400 free(env); 3401 //LOGI("Xit DestroyJNIEnv: threadid=%d %p", self->threadId, self); 3402 } 3403 3404 /* 3405 * Enable "checked JNI" after the VM has partially started. This must 3406 * only be called in "zygote" mode, when we have one thread running. 3407 * 3408 * This doesn't attempt to rewrite the JNI call bridge associated with 3409 * native methods, so we won't get those checks for any methods that have 3410 * already been resolved. 3411 */ 3412 void dvmLateEnableCheckedJni() { 3413 JNIEnvExt* extEnv = dvmGetJNIEnvForThread(); 3414 if (extEnv == NULL) { 3415 LOGE("dvmLateEnableCheckedJni: thread has no JNIEnv"); 3416 return; 3417 } 3418 JavaVMExt* extVm = (JavaVMExt*) gDvmJni.jniVm; 3419 assert(extVm != NULL); 3420 3421 if (!gDvmJni.useCheckJni) { 3422 LOGD("Late-enabling CheckJNI"); 3423 dvmUseCheckedJniVm(extVm); 3424 dvmUseCheckedJniEnv(extEnv); 3425 } else { 3426 LOGD("Not late-enabling CheckJNI (already on)"); 3427 } 3428 } 3429 3430 /* 3431 * Not supported. 3432 */ 3433 jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) { 3434 return JNI_ERR; 3435 } 3436 3437 /* 3438 * Return a buffer full of created VMs. 3439 * 3440 * We always have zero or one. 3441 */ 3442 jint JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs) { 3443 if (gDvmJni.jniVm != NULL) { 3444 *nVMs = 1; 3445 if (bufLen > 0) { 3446 *vmBuf++ = gDvmJni.jniVm; 3447 } 3448 } else { 3449 *nVMs = 0; 3450 } 3451 return JNI_OK; 3452 } 3453 3454 /* 3455 * Create a new VM instance. 3456 * 3457 * The current thread becomes the main VM thread. We return immediately, 3458 * which effectively means the caller is executing in a native method. 3459 */ 3460 jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { 3461 const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args; 3462 if (args->version < JNI_VERSION_1_2) { 3463 return JNI_EVERSION; 3464 } 3465 3466 // TODO: don't allow creation of multiple VMs -- one per customer for now 3467 3468 /* zero globals; not strictly necessary the first time a VM is started */ 3469 memset(&gDvm, 0, sizeof(gDvm)); 3470 3471 /* 3472 * Set up structures for JNIEnv and VM. 3473 */ 3474 JavaVMExt* pVM = (JavaVMExt*) malloc(sizeof(JavaVMExt)); 3475 memset(pVM, 0, sizeof(JavaVMExt)); 3476 pVM->funcTable = &gInvokeInterface; 3477 pVM->envList = NULL; 3478 dvmInitMutex(&pVM->envListLock); 3479 3480 UniquePtr<const char*[]> argv(new const char*[args->nOptions]); 3481 memset(argv.get(), 0, sizeof(char*) * (args->nOptions)); 3482 3483 /* 3484 * Convert JNI args to argv. 3485 * 3486 * We have to pull out vfprintf/exit/abort, because they use the 3487 * "extraInfo" field to pass function pointer "hooks" in. We also 3488 * look for the -Xcheck:jni stuff here. 3489 */ 3490 int argc = 0; 3491 for (int i = 0; i < args->nOptions; i++) { 3492 const char* optStr = args->options[i].optionString; 3493 if (optStr == NULL) { 3494 dvmFprintf(stderr, "ERROR: CreateJavaVM failed: argument %d was NULL\n", i); 3495 return JNI_ERR; 3496 } else if (strcmp(optStr, "vfprintf") == 0) { 3497 gDvm.vfprintfHook = (int (*)(FILE *, const char*, va_list))args->options[i].extraInfo; 3498 } else if (strcmp(optStr, "exit") == 0) { 3499 gDvm.exitHook = (void (*)(int)) args->options[i].extraInfo; 3500 } else if (strcmp(optStr, "abort") == 0) { 3501 gDvm.abortHook = (void (*)(void))args->options[i].extraInfo; 3502 } else if (strcmp(optStr, "sensitiveThread") == 0) { 3503 gDvm.isSensitiveThreadHook = (bool (*)(void))args->options[i].extraInfo; 3504 } else if (strcmp(optStr, "-Xcheck:jni") == 0) { 3505 gDvmJni.useCheckJni = true; 3506 } else if (strncmp(optStr, "-Xjniopts:", 10) == 0) { 3507 char* jniOpts = strdup(optStr + 10); 3508 size_t jniOptCount = 1; 3509 for (char* p = jniOpts; *p != 0; ++p) { 3510 if (*p == ',') { 3511 ++jniOptCount; 3512 *p = 0; 3513 } 3514 } 3515 char* jniOpt = jniOpts; 3516 for (size_t i = 0; i < jniOptCount; ++i) { 3517 if (strcmp(jniOpt, "warnonly") == 0) { 3518 gDvmJni.warnOnly = true; 3519 } else if (strcmp(jniOpt, "forcecopy") == 0) { 3520 gDvmJni.forceCopy = true; 3521 } else if (strcmp(jniOpt, "logThirdPartyJni") == 0) { 3522 gDvmJni.logThirdPartyJni = true; 3523 } else { 3524 dvmFprintf(stderr, "ERROR: CreateJavaVM failed: unknown -Xjniopts option '%s'\n", 3525 jniOpt); 3526 return JNI_ERR; 3527 } 3528 jniOpt += strlen(jniOpt) + 1; 3529 } 3530 free(jniOpts); 3531 } else { 3532 /* regular option */ 3533 argv[argc++] = optStr; 3534 } 3535 } 3536 3537 if (gDvmJni.useCheckJni) { 3538 dvmUseCheckedJniVm(pVM); 3539 } 3540 3541 if (gDvmJni.jniVm != NULL) { 3542 dvmFprintf(stderr, "ERROR: Dalvik only supports one VM per process\n"); 3543 return JNI_ERR; 3544 } 3545 gDvmJni.jniVm = (JavaVM*) pVM; 3546 3547 /* 3548 * Create a JNIEnv for the main thread. We need to have something set up 3549 * here because some of the class initialization we do when starting 3550 * up the VM will call into native code. 3551 */ 3552 JNIEnvExt* pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL); 3553 3554 /* Initialize VM. */ 3555 gDvm.initializing = true; 3556 std::string status = 3557 dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv); 3558 gDvm.initializing = false; 3559 3560 if (!status.empty()) { 3561 free(pEnv); 3562 free(pVM); 3563 LOGW("CreateJavaVM failed: %s", status.c_str()); 3564 return JNI_ERR; 3565 } 3566 3567 /* 3568 * Success! Return stuff to caller. 3569 */ 3570 dvmChangeStatus(NULL, THREAD_NATIVE); 3571 *p_env = (JNIEnv*) pEnv; 3572 *p_vm = (JavaVM*) pVM; 3573 LOGV("CreateJavaVM succeeded"); 3574 return JNI_OK; 3575 } 3576