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