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