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