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