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