2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * Dalvik implementation of JNI interfaces.
21 #include "JniInternal.h"
23 #include "ScopedPthreadMutexLock.h"
24 #include "UniquePtr.h"
31 Native methods and interaction with the GC
33 All JNI methods must start by changing their thread status to
34 THREAD_RUNNING, and finish by changing it back to THREAD_NATIVE before
35 returning to native code. The switch to "running" triggers a thread
38 With a rudimentary GC we should be able to skip the status change for
39 simple functions, e.g. IsSameObject, GetJavaVM, GetStringLength, maybe
40 even access to fields with primitive types. Our options are more limited
43 For performance reasons we do as little error-checking as possible here.
44 For example, we don't check to make sure the correct type of Object is
45 passed in when setting a field, and we don't prevent you from storing
46 new values in a "final" field. Such things are best handled in the
47 "check" version. For actions that are common, dangerous, and must be
48 checked at runtime, such as array bounds checks, we do the tests here.
51 General notes on local/global reference tracking
53 JNI provides explicit control over natively-held references that the GC
54 needs to know about. These can be local, in which case they're released
55 when the native method returns into the VM, or global, which are held
56 until explicitly released. (There are also weak-global references,
57 which have the lifespan and visibility of global references, but the
58 object they refer to may be collected.)
60 The references can be created with explicit JNI NewLocalRef / NewGlobalRef
61 calls. The former is very unusual, the latter is reasonably common
62 (e.g. for caching references to class objects).
64 Local references are most often created as a side-effect of JNI functions.
65 For example, the AllocObject/NewObject functions must create local
66 references to the objects returned, because nothing else in the GC root
67 set has a reference to the new objects.
69 The most common mode of operation is for a method to create zero or
70 more local references and return. Explicit "local delete" operations
71 are expected to be exceedingly rare, except when walking through an
72 object array, and the Push/PopLocalFrame calls are expected to be used
73 infrequently. For efficient operation, we want to add new local refs
74 with a simple store/increment operation; to avoid infinite growth in
75 pathological situations, we need to reclaim the space used by deleted
78 If we just want to maintain a list for the GC root set, we can use an
79 expanding append-only array that compacts when objects are deleted.
80 In typical situations, e.g. running through an array of objects, we will
81 be deleting one of the most recently added entries, so we can minimize
82 the number of elements moved (or avoid having to move any).
84 If we want to conceal the pointer values from native code, which is
85 necessary to allow the GC to move JNI-referenced objects around, then we
86 have to use a more complicated indirection mechanism.
88 The spec says, "Local references are only valid in the thread in which
89 they are created. The native code must not pass local references from
90 one thread to another."
95 For some large chunks of data, notably primitive arrays and String data,
96 JNI allows the VM to choose whether it wants to pin the array object or
97 make a copy. We currently pin the memory for better execution performance.
99 TODO: we're using simple root set references to pin primitive array data,
100 because they have the property we need (i.e. the pointer we return is
101 guaranteed valid until we explicitly release it). However, if we have a
102 compacting GC and don't want to pin all memory held by all global refs,
103 we need to treat these differently.
106 Global reference tracking
108 There should be a small "active" set centered around the most-recently
111 Because it's global, access to it has to be synchronized. Additions and
112 removals require grabbing a mutex. If the table serves as an indirection
113 mechanism (i.e. it's not just a list for the benefit of the garbage
114 collector), reference lookups may also require grabbing a mutex.
116 The JNI spec does not define any sort of limit, so the list must be able
117 to expand to a reasonable size. It may be useful to log significant
118 increases in usage to help identify resource leaks.
121 Weak-global reference tracking
126 Local reference tracking
128 Each Thread/JNIEnv points to an IndirectRefTable.
130 We implement Push/PopLocalFrame with actual stack frames. Before a JNI
131 frame gets popped, we set "nextEntry" to the "top" pointer of the current
132 frame, effectively releasing the references.
134 The GC will scan all references in the table.
138 static void ReportJniError() {
139 dvmDumpThread(dvmThreadSelf(), false);
143 #ifdef WITH_JNI_STACK_CHECK
144 # define COMPUTE_STACK_SUM(_self) computeStackSum(_self);
145 # define CHECK_STACK_SUM(_self) checkStackSum(_self);
148 * Compute a CRC on the entire interpreted stack.
150 * Would be nice to compute it on "self" as well, but there are parts of
151 * the Thread that can be altered by other threads (e.g. prev/next pointers).
153 static void computeStackSum(Thread* self) {
154 const u1* low = (const u1*)SAVEAREA_FROM_FP(self->interpSave.curFrame);
155 u4 crc = dvmInitCrc32();
157 crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
158 self->stackCrc = crc;
162 * Compute a CRC on the entire interpreted stack, and compare it to what
163 * we previously computed.
165 * We can execute JNI directly from native code without calling in from
166 * interpreted code during VM initialization and immediately after JNI
167 * thread attachment. Another opportunity exists during JNI_OnLoad. Rather
168 * than catching these cases we just ignore them here, which is marginally
169 * less accurate but reduces the amount of code we have to touch with #ifdefs.
171 static void checkStackSum(Thread* self) {
172 const u1* low = (const u1*)SAVEAREA_FROM_FP(self->interpSave.curFrame);
173 u4 stackCrc = self->stackCrc;
175 u4 crc = dvmInitCrc32();
176 crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
177 if (crc != stackCrc) {
178 const Method* meth = dvmGetCurrentJNIMethod();
179 if (dvmComputeExactFrameDepth(self->interpSave.curFrame) == 1) {
180 ALOGD("JNI: bad stack CRC (0x%08x) -- okay during init", stackCrc);
181 } else if (strcmp(meth->name, "nativeLoad") == 0 &&
182 (strcmp(meth->clazz->descriptor, "Ljava/lang/Runtime;") == 0)) {
183 ALOGD("JNI: bad stack CRC (0x%08x) -- okay during JNI_OnLoad", stackCrc);
185 ALOGW("JNI: bad stack CRC (%08x vs %08x)", crc, stackCrc);
189 self->stackCrc = (u4) -1; /* make logic errors more noticeable */
193 # define COMPUTE_STACK_SUM(_self) ((void)0)
194 # define CHECK_STACK_SUM(_self) ((void)0)
199 * ===========================================================================
201 * ===========================================================================
205 * Entry/exit processing for all JNI calls.
207 * We skip the (curiously expensive) thread-local storage lookup on our Thread*.
208 * If the caller has passed the wrong JNIEnv in, we're going to be accessing unsynchronized
209 * structures from more than one thread, and things are going to fail
210 * in bizarre ways. This is only sensible if the native code has been
211 * fully exercised with CheckJNI enabled.
213 class ScopedJniThreadState {
215 explicit ScopedJniThreadState(JNIEnv* env) {
216 mSelf = ((JNIEnvExt*) env)->self;
218 if (UNLIKELY(gDvmJni.workAroundAppJniBugs)) {
219 // When emulating direct pointers with indirect references, it's critical
220 // that we use the correct per-thread indirect reference table.
221 Thread* self = gDvmJni.workAroundAppJniBugs ? dvmThreadSelf() : mSelf;
223 ALOGE("JNI ERROR: env->self != thread-self (%p vs. %p); auto-correcting", mSelf, self);
228 CHECK_STACK_SUM(mSelf);
229 dvmChangeStatus(mSelf, THREAD_RUNNING);
232 ~ScopedJniThreadState() {
233 dvmChangeStatus(mSelf, THREAD_NATIVE);
234 COMPUTE_STACK_SUM(mSelf);
237 inline Thread* self() {
244 // Disallow copy and assignment.
245 ScopedJniThreadState(const ScopedJniThreadState&);
246 void operator=(const ScopedJniThreadState&);
249 #define kGlobalRefsTableInitialSize 512
250 #define kGlobalRefsTableMaxSize 51200 /* arbitrary, must be < 64K */
251 #define kGrefWaterInterval 100
252 #define kTrackGrefUsage true
254 #define kWeakGlobalRefsTableInitialSize 16
256 #define kPinTableInitialSize 16
257 #define kPinTableMaxSize 1024
258 #define kPinComplainThreshold 10
260 bool dvmJniStartup() {
261 if (!gDvm.jniGlobalRefTable.init(kGlobalRefsTableInitialSize,
262 kGlobalRefsTableMaxSize,
263 kIndirectKindGlobal)) {
266 if (!gDvm.jniWeakGlobalRefTable.init(kWeakGlobalRefsTableInitialSize,
267 kGlobalRefsTableMaxSize,
268 kIndirectKindWeakGlobal)) {
272 dvmInitMutex(&gDvm.jniGlobalRefLock);
273 dvmInitMutex(&gDvm.jniWeakGlobalRefLock);
274 gDvm.jniGlobalRefLoMark = 0;
275 gDvm.jniGlobalRefHiMark = kGrefWaterInterval * 2;
277 if (!dvmInitReferenceTable(&gDvm.jniPinRefTable, kPinTableInitialSize, kPinTableMaxSize)) {
281 dvmInitMutex(&gDvm.jniPinRefLock);
286 void dvmJniShutdown() {
287 gDvm.jniGlobalRefTable.destroy();
288 gDvm.jniWeakGlobalRefTable.destroy();
289 dvmClearReferenceTable(&gDvm.jniPinRefTable);
293 * Find the JNIEnv associated with the current thread.
295 * Currently stored in the Thread struct. Could also just drop this into
296 * thread-local storage.
298 JNIEnvExt* dvmGetJNIEnvForThread() {
299 Thread* self = dvmThreadSelf();
303 return (JNIEnvExt*) dvmGetThreadJNIEnv(self);
307 * Convert an indirect reference to an Object reference. The indirect
308 * reference may be local, global, or weak-global.
310 * If "jobj" is NULL, or is a weak global reference whose reference has
311 * been cleared, this returns NULL. If jobj is an invalid indirect
312 * reference, kInvalidIndirectRefObject is returned.
314 * Note "env" may be NULL when decoding global references.
316 Object* dvmDecodeIndirectRef(Thread* self, jobject jobj) {
321 switch (indirectRefKind(jobj)) {
322 case kIndirectKindLocal:
324 Object* result = self->jniLocalRefTable.get(jobj);
325 if (UNLIKELY(result == NULL)) {
326 ALOGE("JNI ERROR (app bug): use of deleted local reference (%p)", jobj);
331 case kIndirectKindGlobal:
333 // TODO: find a way to avoid the mutex activity here
334 IndirectRefTable* pRefTable = &gDvm.jniGlobalRefTable;
335 ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
336 Object* result = pRefTable->get(jobj);
337 if (UNLIKELY(result == NULL)) {
338 ALOGE("JNI ERROR (app bug): use of deleted global reference (%p)", jobj);
343 case kIndirectKindWeakGlobal:
345 // TODO: find a way to avoid the mutex activity here
346 IndirectRefTable* pRefTable = &gDvm.jniWeakGlobalRefTable;
347 ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
348 Object* result = pRefTable->get(jobj);
349 if (result == kClearedJniWeakGlobal) {
351 } else if (UNLIKELY(result == NULL)) {
352 ALOGE("JNI ERROR (app bug): use of deleted weak global reference (%p)", jobj);
357 case kIndirectKindInvalid:
359 if (UNLIKELY(gDvmJni.workAroundAppJniBugs)) {
360 // Assume an invalid local reference is actually a direct pointer.
361 return reinterpret_cast<Object*>(jobj);
363 ALOGW("Invalid indirect reference %p in decodeIndirectRef", jobj);
365 return kInvalidIndirectRefObject;
369 static void AddLocalReferenceFailure(IndirectRefTable* pRefTable) {
370 pRefTable->dump("JNI local");
371 ALOGE("Failed adding to JNI local ref table (has %zd entries)", pRefTable->capacity());
372 ReportJniError(); // spec says call FatalError; this is equivalent
376 * Add a local reference for an object to the current stack frame. When
377 * the native function returns, the reference will be discarded.
379 * We need to allow the same reference to be added multiple times.
381 * This will be called on otherwise unreferenced objects. We cannot do
382 * GC allocations here, and it's best if we don't grab a mutex.
384 static inline jobject addLocalReference(Thread* self, Object* obj) {
389 IndirectRefTable* pRefTable = &self->jniLocalRefTable;
390 void* curFrame = self->interpSave.curFrame;
391 u4 cookie = SAVEAREA_FROM_FP(curFrame)->xtra.localRefCookie;
392 jobject jobj = (jobject) pRefTable->add(cookie, obj);
393 if (UNLIKELY(jobj == NULL)) {
394 AddLocalReferenceFailure(pRefTable);
397 if (UNLIKELY(gDvmJni.workAroundAppJniBugs)) {
398 // Hand out direct pointers to support broken old apps.
399 return reinterpret_cast<jobject>(obj);
405 * Ensure that at least "capacity" references can be held in the local
406 * refs table of the current thread.
408 static bool ensureLocalCapacity(Thread* self, int capacity) {
409 int numEntries = self->jniLocalRefTable.capacity();
410 // TODO: this isn't quite right, since "numEntries" includes holes
411 return ((kJniLocalRefMax - numEntries) >= capacity);
415 * Explicitly delete a reference from the local list.
417 static void deleteLocalReference(Thread* self, jobject jobj) {
422 IndirectRefTable* pRefTable = &self->jniLocalRefTable;
423 void* curFrame = self->interpSave.curFrame;
424 u4 cookie = SAVEAREA_FROM_FP(curFrame)->xtra.localRefCookie;
425 if (!pRefTable->remove(cookie, jobj)) {
427 * Attempting to delete a local reference that is not in the
428 * topmost local reference frame is a no-op. DeleteLocalRef returns
429 * void and doesn't throw any exceptions, but we should probably
430 * complain about it so the user will notice that things aren't
431 * going quite the way they expect.
433 ALOGW("JNI WARNING: DeleteLocalRef(%p) failed to find entry", jobj);
438 * Add a global reference for an object.
440 * We may add the same object more than once. Add/remove calls are paired,
441 * so it needs to appear on the list multiple times.
443 static jobject addGlobalReference(Object* obj) {
448 //ALOGI("adding obj=%p", obj);
449 //dvmDumpThread(dvmThreadSelf(), false);
451 if (false && dvmIsClassObject((Object*)obj)) {
452 ClassObject* clazz = (ClassObject*) obj;
454 ALOGI("Adding global ref on class %s", clazz->descriptor);
455 dvmDumpThread(dvmThreadSelf(), false);
457 if (false && ((Object*)obj)->clazz == gDvm.classJavaLangString) {
458 StringObject* strObj = (StringObject*) obj;
459 char* str = dvmCreateCstrFromString(strObj);
460 if (strcmp(str, "sync-response") == 0) {
462 ALOGI("Adding global ref on string '%s'", str);
463 dvmDumpThread(dvmThreadSelf(), false);
468 if (false && ((Object*)obj)->clazz == gDvm.classArrayByte) {
469 ArrayObject* arrayObj = (ArrayObject*) obj;
470 if (arrayObj->length == 8192 /*&&
471 dvmReferenceTableEntries(&gDvm.jniGlobalRefTable) > 400*/)
473 ALOGI("Adding global ref on byte array %p (len=%d)",
474 arrayObj, arrayObj->length);
475 dvmDumpThread(dvmThreadSelf(), false);
479 ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
482 * Throwing an exception on failure is problematic, because JNI code
483 * may not be expecting an exception, and things sort of cascade. We
484 * want to have a hard limit to catch leaks during debugging, but this
485 * otherwise needs to expand until memory is consumed. As a practical
486 * matter, if we have many thousands of global references, chances are
487 * we're either leaking global ref table entries or we're going to
488 * run out of space in the GC heap.
490 jobject jobj = (jobject) gDvm.jniGlobalRefTable.add(IRT_FIRST_SEGMENT, obj);
492 gDvm.jniGlobalRefTable.dump("JNI global");
493 ALOGE("Failed adding to JNI global ref table (%zd entries)",
494 gDvm.jniGlobalRefTable.capacity());
498 LOGVV("GREF add %p (%s.%s)", obj,
499 dvmGetCurrentJNIMethod()->clazz->descriptor,
500 dvmGetCurrentJNIMethod()->name);
502 /* GREF usage tracking; should probably be disabled for production env */
503 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
504 int count = gDvm.jniGlobalRefTable.capacity();
505 // TODO: adjust for "holes"
506 if (count > gDvm.jniGlobalRefHiMark) {
507 ALOGD("GREF has increased to %d", count);
508 gDvm.jniGlobalRefHiMark += kGrefWaterInterval;
509 gDvm.jniGlobalRefLoMark += kGrefWaterInterval;
511 /* watch for "excessive" use; not generally appropriate */
512 if (count >= gDvm.jniGrefLimit) {
513 if (gDvmJni.warnOnly) {
514 ALOGW("Excessive JNI global references (%d)", count);
516 gDvm.jniGlobalRefTable.dump("JNI global");
517 ALOGE("Excessive JNI global references (%d)", count);
526 static jobject addWeakGlobalReference(Object* obj) {
531 ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
532 IndirectRefTable *table = &gDvm.jniWeakGlobalRefTable;
533 jobject jobj = (jobject) table->add(IRT_FIRST_SEGMENT, obj);
535 gDvm.jniWeakGlobalRefTable.dump("JNI weak global");
536 ALOGE("Failed adding to JNI weak global ref table (%zd entries)", table->capacity());
542 static void deleteWeakGlobalReference(jobject jobj) {
547 ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
548 IndirectRefTable *table = &gDvm.jniWeakGlobalRefTable;
549 if (!table->remove(IRT_FIRST_SEGMENT, jobj)) {
550 ALOGW("JNI: DeleteWeakGlobalRef(%p) failed to find entry", jobj);
555 * Remove a global reference. In most cases it's the entry most recently
556 * added, which makes this pretty quick.
558 * Thought: if it's not the most recent entry, just null it out. When we
559 * fill up, do a compaction pass before we expand the list.
561 static void deleteGlobalReference(jobject jobj) {
566 ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
567 if (!gDvm.jniGlobalRefTable.remove(IRT_FIRST_SEGMENT, jobj)) {
568 ALOGW("JNI: DeleteGlobalRef(%p) failed to find entry", jobj);
572 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
573 int count = gDvm.jniGlobalRefTable.capacity();
574 // TODO: not quite right, need to subtract holes
575 if (count < gDvm.jniGlobalRefLoMark) {
576 ALOGD("GREF has decreased to %d", count);
577 gDvm.jniGlobalRefHiMark -= kGrefWaterInterval;
578 gDvm.jniGlobalRefLoMark -= kGrefWaterInterval;
584 * Objects don't currently move, so we just need to create a reference
585 * that will ensure the array object isn't collected.
587 * We use a separate reference table, which is part of the GC root set.
589 static void pinPrimitiveArray(ArrayObject* arrayObj) {
590 if (arrayObj == NULL) {
594 ScopedPthreadMutexLock lock(&gDvm.jniPinRefLock);
596 if (!dvmAddToReferenceTable(&gDvm.jniPinRefTable, (Object*)arrayObj)) {
597 dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
598 ALOGE("Failed adding to JNI pinned array ref table (%d entries)",
599 (int) dvmReferenceTableEntries(&gDvm.jniPinRefTable));
604 * If we're watching global ref usage, also keep an eye on these.
606 * The total number of pinned primitive arrays should be pretty small.
607 * A single array should not be pinned more than once or twice; any
608 * more than that is a strong indicator that a Release function is
611 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
613 Object** ppObj = gDvm.jniPinRefTable.table;
614 while (ppObj < gDvm.jniPinRefTable.nextEntry) {
615 if (*ppObj++ == (Object*) arrayObj)
619 if (count > kPinComplainThreshold) {
620 ALOGW("JNI: pin count on array %p (%s) is now %d",
621 arrayObj, arrayObj->clazz->descriptor, count);
628 * Un-pin the array object. If an object was pinned twice, it must be
629 * unpinned twice before it's free to move.
631 static void unpinPrimitiveArray(ArrayObject* arrayObj) {
632 if (arrayObj == NULL) {
636 ScopedPthreadMutexLock lock(&gDvm.jniPinRefLock);
637 if (!dvmRemoveFromReferenceTable(&gDvm.jniPinRefTable,
638 gDvm.jniPinRefTable.table, (Object*) arrayObj))
640 ALOGW("JNI: unpinPrimitiveArray(%p) failed to find entry (valid=%d)",
641 arrayObj, dvmIsHeapAddress((Object*) arrayObj));
647 * Dump the contents of the JNI reference tables to the log file.
649 * We only dump the local refs associated with the current thread.
651 void dvmDumpJniReferenceTables() {
652 Thread* self = dvmThreadSelf();
653 self->jniLocalRefTable.dump("JNI local");
654 gDvm.jniGlobalRefTable.dump("JNI global");
655 dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
658 void dvmDumpJniStats(DebugOutputTarget* target) {
659 dvmPrintDebugMessage(target, "JNI: CheckJNI is %s", gDvmJni.useCheckJni ? "on" : "off");
660 if (gDvmJni.forceCopy) {
661 dvmPrintDebugMessage(target, " (with forcecopy)");
663 dvmPrintDebugMessage(target, "; workarounds are %s", gDvmJni.workAroundAppJniBugs ? "on" : "off");
665 dvmLockMutex(&gDvm.jniPinRefLock);
666 dvmPrintDebugMessage(target, "; pins=%d", dvmReferenceTableEntries(&gDvm.jniPinRefTable));
667 dvmUnlockMutex(&gDvm.jniPinRefLock);
669 dvmLockMutex(&gDvm.jniGlobalRefLock);
670 dvmPrintDebugMessage(target, "; globals=%d", gDvm.jniGlobalRefTable.capacity());
671 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
673 dvmLockMutex(&gDvm.jniWeakGlobalRefLock);
674 size_t weaks = gDvm.jniWeakGlobalRefTable.capacity();
676 dvmPrintDebugMessage(target, " (plus %d weak)", weaks);
678 dvmUnlockMutex(&gDvm.jniWeakGlobalRefLock);
680 dvmPrintDebugMessage(target, "\n\n");
684 * Verify that a reference passed in from native code is one that the
685 * code is allowed to have.
687 * It's okay for native code to pass us a reference that:
688 * - was passed in as an argument when invoked by native code (and hence
689 * is in the JNI local refs table)
690 * - was returned to it from JNI (and is now in the local refs table)
691 * - is present in the JNI global refs table
693 * Used by -Xcheck:jni and GetObjectRefType.
695 jobjectRefType dvmGetJNIRefType(Thread* self, jobject jobj) {
697 * IndirectRefKind is currently defined as an exact match of
698 * jobjectRefType, so this is easy. We have to decode it to determine
699 * if it's a valid reference and not merely valid-looking.
701 assert(jobj != NULL);
703 Object* obj = dvmDecodeIndirectRef(self, jobj);
704 if (obj == reinterpret_cast<Object*>(jobj) && gDvmJni.workAroundAppJniBugs) {
705 // If we're handing out direct pointers, check whether 'jobj' is a direct reference
706 // to a local reference.
707 return self->jniLocalRefTable.contains(obj) ? JNILocalRefType : JNIInvalidRefType;
708 } else if (obj == kInvalidIndirectRefObject) {
709 return JNIInvalidRefType;
711 return (jobjectRefType) indirectRefKind(jobj);
715 static void dumpMethods(Method* methods, size_t methodCount, const char* name) {
717 for (i = 0; i < methodCount; ++i) {
718 Method* method = &methods[i];
719 if (strcmp(name, method->name) == 0) {
720 char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
721 ALOGE("Candidate: %s.%s:%s", method->clazz->descriptor, name, desc);
727 static void dumpCandidateMethods(ClassObject* clazz, const char* methodName, const char* signature) {
728 ALOGE("ERROR: couldn't find native method");
729 ALOGE("Requested: %s.%s:%s", clazz->descriptor, methodName, signature);
730 dumpMethods(clazz->virtualMethods, clazz->virtualMethodCount, methodName);
731 dumpMethods(clazz->directMethods, clazz->directMethodCount, methodName);
735 * Register a method that uses JNI calling conventions.
737 static bool dvmRegisterJNIMethod(ClassObject* clazz, const char* methodName,
738 const char* signature, void* fnPtr)
744 // If a signature starts with a '!', we take that as a sign that the native code doesn't
745 // need the extra JNI arguments (the JNIEnv* and the jclass).
746 bool fastJni = false;
747 if (*signature == '!') {
750 ALOGV("fast JNI method %s.%s:%s detected", clazz->descriptor, methodName, signature);
753 Method* method = dvmFindDirectMethodByDescriptor(clazz, methodName, signature);
754 if (method == NULL) {
755 method = dvmFindVirtualMethodByDescriptor(clazz, methodName, signature);
757 if (method == NULL) {
758 dumpCandidateMethods(clazz, methodName, signature);
762 if (!dvmIsNativeMethod(method)) {
763 ALOGW("Unable to register: not native: %s.%s:%s", clazz->descriptor, methodName, signature);
768 // In this case, we have extra constraints to check...
769 if (dvmIsSynchronizedMethod(method)) {
770 // Synchronization is usually provided by the JNI bridge,
771 // but we won't have one.
772 ALOGE("fast JNI method %s.%s:%s cannot be synchronized",
773 clazz->descriptor, methodName, signature);
776 if (!dvmIsStaticMethod(method)) {
777 // There's no real reason for this constraint, but since we won't
778 // be supplying a JNIEnv* or a jobject 'this', you're effectively
779 // static anyway, so it seems clearer to say so.
780 ALOGE("fast JNI method %s.%s:%s cannot be non-static",
781 clazz->descriptor, methodName, signature);
786 if (method->nativeFunc != dvmResolveNativeMethod) {
787 /* this is allowed, but unusual */
788 ALOGV("Note: %s.%s:%s was already registered", clazz->descriptor, methodName, signature);
791 method->fastJni = fastJni;
792 dvmUseJNIBridge(method, fnPtr);
794 ALOGV("JNI-registered %s.%s:%s", clazz->descriptor, methodName, signature);
798 static const char* builtInPrefixes[] = {
801 "Lcom/google/android/",
806 "Lorg/apache/harmony/",
809 static bool shouldTrace(Method* method) {
810 const char* className = method->clazz->descriptor;
811 // Return true if the -Xjnitrace setting implies we should trace 'method'.
812 if (gDvm.jniTrace && strstr(className, gDvm.jniTrace)) {
815 // Return true if we're trying to log all third-party JNI activity and 'method' doesn't look
816 // like part of Android.
817 if (gDvmJni.logThirdPartyJni) {
818 for (size_t i = 0; i < NELEM(builtInPrefixes); ++i) {
819 if (strstr(className, builtInPrefixes[i]) == className) {
829 * Point "method->nativeFunc" at the JNI bridge, and overload "method->insns"
830 * to point at the actual function.
832 void dvmUseJNIBridge(Method* method, void* func) {
833 method->shouldTrace = shouldTrace(method);
835 // Does the method take any reference arguments?
836 method->noRef = true;
837 const char* cp = method->shorty;
838 while (*++cp != '\0') { // Pre-increment to skip return type.
840 method->noRef = false;
845 DalvikBridgeFunc bridge = gDvmJni.useCheckJni ? dvmCheckCallJNIMethod : dvmCallJNIMethod;
846 dvmSetNativeFunc(method, bridge, (const u2*) func);
849 // TODO: rewrite this to share code with CheckJNI's tracing...
850 static void appendValue(char type, const JValue value, char* buf, size_t n, bool appendComma)
852 size_t len = strlen(buf);
853 if (len >= n - 32) { // 32 should be longer than anything we could append.
862 if (value.b >= 0 && value.b < 10) {
863 sprintf(p, "%d", value.b);
865 sprintf(p, "%#x (%d)", value.b, value.b);
869 if (value.c < 0x7f && value.c >= ' ') {
870 sprintf(p, "U+%x ('%c')", value.c, value.c);
872 sprintf(p, "U+%x", value.c);
876 sprintf(p, "%g", value.d);
879 sprintf(p, "%g", value.f);
882 sprintf(p, "%d", value.i);
885 sprintf(p, "%#x", value.i);
888 sprintf(p, "%lld", value.j);
891 sprintf(p, "%d", value.s);
897 strcpy(p, value.z ? "true" : "false");
900 sprintf(p, "unknown type '%c'", type);
909 static void logNativeMethodEntry(const Method* method, const u4* args)
911 char thisString[32] = { 0 };
913 if (!dvmIsStaticMethod(method)) {
914 sprintf(thisString, "this=0x%08x ", *sp++);
917 char argsString[128]= { 0 };
918 const char* desc = &method->shorty[1];
919 while (*desc != '\0') {
920 char argType = *desc++;
922 if (argType == 'D' || argType == 'J') {
923 value.j = dvmGetArgLong(sp, 0);
928 appendValue(argType, value, argsString, sizeof(argsString),
932 std::string className(dvmHumanReadableDescriptor(method->clazz->descriptor));
933 char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
934 ALOGI("-> %s %s%s %s(%s)", className.c_str(), method->name, signature, thisString, argsString);
938 static void logNativeMethodExit(const Method* method, Thread* self, const JValue returnValue)
940 std::string className(dvmHumanReadableDescriptor(method->clazz->descriptor));
941 char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
942 if (dvmCheckException(self)) {
943 Object* exception = dvmGetException(self);
944 std::string exceptionClassName(dvmHumanReadableDescriptor(exception->clazz->descriptor));
945 ALOGI("<- %s %s%s threw %s", className.c_str(),
946 method->name, signature, exceptionClassName.c_str());
948 char returnValueString[128] = { 0 };
949 char returnType = method->shorty[0];
950 appendValue(returnType, returnValue, returnValueString, sizeof(returnValueString), false);
951 ALOGI("<- %s %s%s returned %s", className.c_str(),
952 method->name, signature, returnValueString);
958 * Get the method currently being executed by examining the interp stack.
960 const Method* dvmGetCurrentJNIMethod() {
961 assert(dvmThreadSelf() != NULL);
963 void* fp = dvmThreadSelf()->interpSave.curFrame;
964 const Method* meth = SAVEAREA_FROM_FP(fp)->method;
966 assert(meth != NULL);
967 assert(dvmIsNativeMethod(meth));
972 * Track a JNI MonitorEnter in the current thread.
974 * The goal is to be able to "implicitly" release all JNI-held monitors
975 * when the thread detaches.
977 * Monitors may be entered multiple times, so we add a new entry for each
978 * enter call. It would be more efficient to keep a counter. At present
979 * there's no real motivation to improve this however.
981 static void trackMonitorEnter(Thread* self, Object* obj) {
982 static const int kInitialSize = 16;
983 ReferenceTable* refTable = &self->jniMonitorRefTable;
985 /* init table on first use */
986 if (refTable->table == NULL) {
987 assert(refTable->maxEntries == 0);
989 if (!dvmInitReferenceTable(refTable, kInitialSize, INT_MAX)) {
990 ALOGE("Unable to initialize monitor tracking table");
995 if (!dvmAddToReferenceTable(refTable, obj)) {
996 /* ran out of memory? could throw exception instead */
997 ALOGE("Unable to add entry to monitor tracking table");
1000 LOGVV("--- added monitor %p", obj);
1005 * Track a JNI MonitorExit in the current thread.
1007 static void trackMonitorExit(Thread* self, Object* obj) {
1008 ReferenceTable* pRefTable = &self->jniMonitorRefTable;
1010 if (!dvmRemoveFromReferenceTable(pRefTable, pRefTable->table, obj)) {
1011 ALOGE("JNI monitor %p not found in tracking list", obj);
1014 LOGVV("--- removed monitor %p", obj);
1019 * Release all monitors held by the jniMonitorRefTable list.
1021 void dvmReleaseJniMonitors(Thread* self) {
1022 ReferenceTable* pRefTable = &self->jniMonitorRefTable;
1023 Object** top = pRefTable->table;
1028 Object** ptr = pRefTable->nextEntry;
1029 while (--ptr >= top) {
1030 if (!dvmUnlockObject(self, *ptr)) {
1031 ALOGW("Unable to unlock monitor %p at thread detach", *ptr);
1033 LOGVV("--- detach-releasing monitor %p", *ptr);
1038 pRefTable->nextEntry = pRefTable->table;
1042 * Determine if the specified class can be instantiated from JNI. This
1043 * is used by AllocObject / NewObject, which are documented as throwing
1044 * an exception for abstract and interface classes, and not accepting
1045 * array classes. We also want to reject attempts to create new Class
1046 * objects, since only DefineClass should do that.
1048 static bool canAllocClass(ClassObject* clazz) {
1049 if (dvmIsAbstractClass(clazz) || dvmIsInterfaceClass(clazz)) {
1050 /* JNI spec defines what this throws */
1051 dvmThrowInstantiationException(clazz, "abstract class or interface");
1053 } else if (dvmIsArrayClass(clazz) || dvmIsTheClassClass(clazz)) {
1054 /* spec says "must not" for arrays, ignores Class */
1055 dvmThrowInstantiationException(clazz, "wrong JNI function");
1063 * ===========================================================================
1065 * ===========================================================================
1069 * The functions here form a bridge between interpreted code and JNI native
1070 * functions. The basic task is to convert an array of primitives and
1071 * references into C-style function arguments. This is architecture-specific
1072 * and usually requires help from assembly code.
1074 * The bridge takes four arguments: the array of parameters, a place to
1075 * store the function result (if any), the method to call, and a pointer
1076 * to the current thread.
1078 * These functions aren't called directly from elsewhere in the VM.
1079 * A pointer in the Method struct points to one of these, and when a native
1080 * method is invoked the interpreter jumps to it.
1082 * (The "internal native" methods are invoked the same way, but instead
1083 * of calling through a bridge, the target method is called directly.)
1085 * The "args" array should not be modified, but we do so anyway for
1086 * performance reasons. We know that it points to the "outs" area on
1087 * the current method's interpreted stack. This area is ignored by the
1088 * precise GC, because there is no register map for a native method (for
1089 * an interpreted method the args would be listed in the argument set).
1090 * We know all of the values exist elsewhere on the interpreted stack,
1091 * because the method call setup copies them right before making the call,
1092 * so we don't have to worry about concealing stuff from the GC.
1094 * If we don't want to modify "args", we either have to create a local
1095 * copy and modify it before calling dvmPlatformInvoke, or we have to do
1096 * the local reference replacement within dvmPlatformInvoke. The latter
1097 * has some performance advantages, though if we can inline the local
1098 * reference adds we may win when there's a lot of reference args (unless
1099 * we want to code up some local ref table manipulation in assembly.
1103 * If necessary, convert the value in pResult from a local/global reference
1104 * to an object pointer.
1106 * If the returned reference is invalid, kInvalidIndirectRefObject will
1107 * be returned in pResult.
1109 static inline void convertReferenceResult(JNIEnv* env, JValue* pResult,
1110 const Method* method, Thread* self)
1112 if (method->shorty[0] == 'L' && !dvmCheckException(self) && pResult->l != NULL) {
1113 pResult->l = dvmDecodeIndirectRef(self, (jobject) pResult->l);
1118 * General form, handles all cases.
1120 void dvmCallJNIMethod(const u4* args, JValue* pResult, const Method* method, Thread* self) {
1121 u4* modArgs = (u4*) args;
1122 jclass staticMethodClass = NULL;
1124 u4 accessFlags = method->accessFlags;
1125 bool isSynchronized = (accessFlags & ACC_SYNCHRONIZED) != 0;
1127 //ALOGI("JNI calling %p (%s.%s:%s):", method->insns,
1128 // method->clazz->descriptor, method->name, method->shorty);
1131 * Walk the argument list, creating local references for appropriate
1136 if ((accessFlags & ACC_STATIC) != 0) {
1137 lockObj = (Object*) method->clazz;
1138 /* add the class object we pass in */
1139 staticMethodClass = (jclass) addLocalReference(self, (Object*) method->clazz);
1141 lockObj = (Object*) args[0];
1143 modArgs[idx++] = (u4) addLocalReference(self, (Object*) modArgs[0]);
1146 if (!method->noRef) {
1147 const char* shorty = &method->shorty[1]; /* skip return type */
1148 while (*shorty != '\0') {
1149 switch (*shorty++) {
1151 //ALOGI(" local %d: 0x%08x", idx, modArgs[idx]);
1152 if (modArgs[idx] != 0) {
1153 modArgs[idx] = (u4) addLocalReference(self, (Object*) modArgs[idx]);
1161 /* Z B C S I -- do nothing */
1168 if (UNLIKELY(method->shouldTrace)) {
1169 logNativeMethodEntry(method, args);
1171 if (UNLIKELY(isSynchronized)) {
1172 dvmLockObject(self, lockObj);
1175 ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
1177 ANDROID_MEMBAR_FULL(); /* guarantee ordering on method->insns */
1178 assert(method->insns != NULL);
1180 JNIEnv* env = self->jniEnv;
1181 COMPUTE_STACK_SUM(self);
1182 dvmPlatformInvoke(env,
1183 (ClassObject*) staticMethodClass,
1184 method->jniArgInfo, method->insSize, modArgs, method->shorty,
1185 (void*) method->insns, pResult);
1186 CHECK_STACK_SUM(self);
1188 dvmChangeStatus(self, oldStatus);
1190 convertReferenceResult(env, pResult, method, self);
1192 if (UNLIKELY(isSynchronized)) {
1193 dvmUnlockObject(self, lockObj);
1195 if (UNLIKELY(method->shouldTrace)) {
1196 logNativeMethodExit(method, self, *pResult);
1201 * ===========================================================================
1202 * JNI implementation
1203 * ===========================================================================
1207 * Return the version of the native method interface.
1209 static jint GetVersion(JNIEnv* env) {
1211 * There is absolutely no need to toggle the mode for correct behavior.
1212 * However, it does provide native code with a simple "suspend self
1213 * if necessary" call.
1215 ScopedJniThreadState ts(env);
1216 return JNI_VERSION_1_6;
1220 * Create a new class from a bag of bytes.
1222 * This is not currently supported within Dalvik.
1224 static jclass DefineClass(JNIEnv* env, const char *name, jobject loader,
1225 const jbyte* buf, jsize bufLen)
1227 UNUSED_PARAMETER(name);
1228 UNUSED_PARAMETER(loader);
1229 UNUSED_PARAMETER(buf);
1230 UNUSED_PARAMETER(bufLen);
1232 ScopedJniThreadState ts(env);
1233 ALOGW("JNI DefineClass is not supported");
1238 * Find a class by name.
1240 * We have to use the "no init" version of FindClass here, because we might
1241 * be getting the class prior to registering native methods that will be
1244 * We need to get the class loader associated with the current native
1245 * method. If there is no native method, e.g. we're calling this from native
1246 * code right after creating the VM, the spec says we need to use the class
1247 * loader returned by "ClassLoader.getBaseClassLoader". There is no such
1248 * method, but it's likely they meant ClassLoader.getSystemClassLoader.
1249 * We can't get that until after the VM has initialized though.
1251 static jclass FindClass(JNIEnv* env, const char* name) {
1252 ScopedJniThreadState ts(env);
1254 const Method* thisMethod = dvmGetCurrentJNIMethod();
1255 assert(thisMethod != NULL);
1258 Object* trackedLoader = NULL;
1259 if (ts.self()->classLoaderOverride != NULL) {
1260 /* hack for JNI_OnLoad */
1261 assert(strcmp(thisMethod->name, "nativeLoad") == 0);
1262 loader = ts.self()->classLoaderOverride;
1263 } else if (thisMethod == gDvm.methDalvikSystemNativeStart_main ||
1264 thisMethod == gDvm.methDalvikSystemNativeStart_run) {
1265 /* start point of invocation interface */
1266 if (!gDvm.initializing) {
1267 loader = trackedLoader = dvmGetSystemClassLoader();
1272 loader = thisMethod->clazz->classLoader;
1275 char* descriptor = dvmNameToDescriptor(name);
1276 if (descriptor == NULL) {
1279 ClassObject* clazz = dvmFindClassNoInit(descriptor, loader);
1282 jclass jclazz = (jclass) addLocalReference(ts.self(), (Object*) clazz);
1283 dvmReleaseTrackedAlloc(trackedLoader, ts.self());
1288 * Return the superclass of a class.
1290 static jclass GetSuperclass(JNIEnv* env, jclass jclazz) {
1291 ScopedJniThreadState ts(env);
1292 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1293 return (jclass) addLocalReference(ts.self(), (Object*)clazz->super);
1297 * Determine whether an object of clazz1 can be safely cast to clazz2.
1299 * Like IsInstanceOf, but with a pair of class objects instead of obj+class.
1301 static jboolean IsAssignableFrom(JNIEnv* env, jclass jclazz1, jclass jclazz2) {
1302 ScopedJniThreadState ts(env);
1303 ClassObject* clazz1 = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz1);
1304 ClassObject* clazz2 = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz2);
1305 return dvmInstanceof(clazz1, clazz2);
1309 * Given a java.lang.reflect.Method or .Constructor, return a methodID.
1311 static jmethodID FromReflectedMethod(JNIEnv* env, jobject jmethod) {
1312 ScopedJniThreadState ts(env);
1313 Object* method = dvmDecodeIndirectRef(ts.self(), jmethod);
1314 return (jmethodID) dvmGetMethodFromReflectObj(method);
1318 * Given a java.lang.reflect.Field, return a fieldID.
1320 static jfieldID FromReflectedField(JNIEnv* env, jobject jfield) {
1321 ScopedJniThreadState ts(env);
1322 Object* field = dvmDecodeIndirectRef(ts.self(), jfield);
1323 return (jfieldID) dvmGetFieldFromReflectObj(field);
1327 * Convert a methodID to a java.lang.reflect.Method or .Constructor.
1329 * (The "isStatic" field does not appear in the spec.)
1331 * Throws OutOfMemory and returns NULL on failure.
1333 static jobject ToReflectedMethod(JNIEnv* env, jclass jcls, jmethodID methodID, jboolean isStatic) {
1334 ScopedJniThreadState ts(env);
1335 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jcls);
1336 Object* obj = dvmCreateReflectObjForMethod(clazz, (Method*) methodID);
1337 dvmReleaseTrackedAlloc(obj, NULL);
1338 return addLocalReference(ts.self(), obj);
1342 * Convert a fieldID to a java.lang.reflect.Field.
1344 * (The "isStatic" field does not appear in the spec.)
1346 * Throws OutOfMemory and returns NULL on failure.
1348 static jobject ToReflectedField(JNIEnv* env, jclass jcls, jfieldID fieldID, jboolean isStatic) {
1349 ScopedJniThreadState ts(env);
1350 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jcls);
1351 Object* obj = dvmCreateReflectObjForField(clazz, (Field*) fieldID);
1352 dvmReleaseTrackedAlloc(obj, NULL);
1353 return addLocalReference(ts.self(), obj);
1357 * Take this exception and throw it.
1359 static jint Throw(JNIEnv* env, jthrowable jobj) {
1360 ScopedJniThreadState ts(env);
1362 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1363 dvmSetException(ts.self(), obj);
1370 * Constructs an exception object from the specified class with the message
1371 * specified by "message", and throws it.
1373 static jint ThrowNew(JNIEnv* env, jclass jclazz, const char* message) {
1374 ScopedJniThreadState ts(env);
1375 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1376 dvmThrowException(clazz, message);
1377 // TODO: should return failure if this didn't work (e.g. OOM)
1382 * If an exception is being thrown, return the exception object. Otherwise,
1385 * TODO: if there is no pending exception, we should be able to skip the
1386 * enter/exit checks. If we find one, we need to enter and then re-fetch
1387 * the exception (in case it got moved by a compacting GC).
1389 static jthrowable ExceptionOccurred(JNIEnv* env) {
1390 ScopedJniThreadState ts(env);
1391 Object* exception = dvmGetException(ts.self());
1392 jthrowable localException = (jthrowable) addLocalReference(ts.self(), exception);
1393 if (localException == NULL && exception != NULL) {
1395 * We were unable to add a new local reference, and threw a new
1396 * exception. We can't return "exception", because it's not a
1397 * local reference. So we have to return NULL, indicating that
1398 * there was no exception, even though it's pretty much raining
1399 * exceptions in here.
1401 ALOGW("JNI WARNING: addLocal/exception combo");
1403 return localException;
1407 * Print an exception and stack trace to stderr.
1409 static void ExceptionDescribe(JNIEnv* env) {
1410 ScopedJniThreadState ts(env);
1411 Object* exception = dvmGetException(ts.self());
1412 if (exception != NULL) {
1413 dvmPrintExceptionStackTrace();
1415 ALOGI("Odd: ExceptionDescribe called, but no exception pending");
1420 * Clear the exception currently being thrown.
1422 * TODO: we should be able to skip the enter/exit stuff.
1424 static void ExceptionClear(JNIEnv* env) {
1425 ScopedJniThreadState ts(env);
1426 dvmClearException(ts.self());
1430 * Kill the VM. This function does not return.
1432 static void FatalError(JNIEnv* env, const char* msg) {
1433 //dvmChangeStatus(NULL, THREAD_RUNNING);
1434 ALOGE("JNI posting fatal error: %s", msg);
1439 * Push a new JNI frame on the stack, with a new set of locals.
1441 * The new frame must have the same method pointer. (If for no other
1442 * reason than FindClass needs it to get the appropriate class loader.)
1444 static jint PushLocalFrame(JNIEnv* env, jint capacity) {
1445 ScopedJniThreadState ts(env);
1446 if (!ensureLocalCapacity(ts.self(), capacity) ||
1447 !dvmPushLocalFrame(ts.self(), dvmGetCurrentJNIMethod()))
1449 /* yes, OutOfMemoryError, not StackOverflowError */
1450 dvmClearException(ts.self());
1451 dvmThrowOutOfMemoryError("out of stack in JNI PushLocalFrame");
1458 * Pop the local frame off. If "jresult" is not null, add it as a
1459 * local reference on the now-current frame.
1461 static jobject PopLocalFrame(JNIEnv* env, jobject jresult) {
1462 ScopedJniThreadState ts(env);
1463 Object* result = dvmDecodeIndirectRef(ts.self(), jresult);
1464 if (!dvmPopLocalFrame(ts.self())) {
1465 ALOGW("JNI WARNING: too many PopLocalFrame calls");
1466 dvmClearException(ts.self());
1467 dvmThrowRuntimeException("too many PopLocalFrame calls");
1469 return addLocalReference(ts.self(), result);
1473 * Add a reference to the global list.
1475 static jobject NewGlobalRef(JNIEnv* env, jobject jobj) {
1476 ScopedJniThreadState ts(env);
1477 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1478 return addGlobalReference(obj);
1482 * Delete a reference from the global list.
1484 static void DeleteGlobalRef(JNIEnv* env, jobject jglobalRef) {
1485 ScopedJniThreadState ts(env);
1486 deleteGlobalReference(jglobalRef);
1491 * Add a reference to the local list.
1493 static jobject NewLocalRef(JNIEnv* env, jobject jobj) {
1494 ScopedJniThreadState ts(env);
1495 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1496 return addLocalReference(ts.self(), obj);
1500 * Delete a reference from the local list.
1502 static void DeleteLocalRef(JNIEnv* env, jobject jlocalRef) {
1503 ScopedJniThreadState ts(env);
1504 deleteLocalReference(ts.self(), jlocalRef);
1508 * Ensure that the local references table can hold at least this many
1511 static jint EnsureLocalCapacity(JNIEnv* env, jint capacity) {
1512 ScopedJniThreadState ts(env);
1513 bool okay = ensureLocalCapacity(ts.self(), capacity);
1515 dvmThrowOutOfMemoryError("can't ensure local reference capacity");
1517 return okay ? 0 : -1;
1522 * Determine whether two Object references refer to the same underlying object.
1524 static jboolean IsSameObject(JNIEnv* env, jobject jref1, jobject jref2) {
1525 ScopedJniThreadState ts(env);
1526 Object* obj1 = dvmDecodeIndirectRef(ts.self(), jref1);
1527 Object* obj2 = dvmDecodeIndirectRef(ts.self(), jref2);
1528 return (obj1 == obj2);
1532 * Allocate a new object without invoking any constructors.
1534 static jobject AllocObject(JNIEnv* env, jclass jclazz) {
1535 ScopedJniThreadState ts(env);
1537 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1538 if (!canAllocClass(clazz) ||
1539 (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)))
1541 assert(dvmCheckException(ts.self()));
1545 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1546 return addLocalReference(ts.self(), newObj);
1550 * Allocate a new object and invoke the supplied constructor.
1552 static jobject NewObject(JNIEnv* env, jclass jclazz, jmethodID methodID, ...) {
1553 ScopedJniThreadState ts(env);
1554 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1556 if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
1557 assert(dvmCheckException(ts.self()));
1561 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1562 jobject result = addLocalReference(ts.self(), newObj);
1563 if (newObj != NULL) {
1566 va_start(args, methodID);
1567 dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args);
1573 static jobject NewObjectV(JNIEnv* env, jclass jclazz, jmethodID methodID, va_list args) {
1574 ScopedJniThreadState ts(env);
1575 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1577 if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
1578 assert(dvmCheckException(ts.self()));
1582 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1583 jobject result = addLocalReference(ts.self(), newObj);
1584 if (newObj != NULL) {
1586 dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args);
1591 static jobject NewObjectA(JNIEnv* env, jclass jclazz, jmethodID methodID, jvalue* args) {
1592 ScopedJniThreadState ts(env);
1593 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1595 if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
1596 assert(dvmCheckException(ts.self()));
1600 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1601 jobject result = addLocalReference(ts.self(), newObj);
1602 if (newObj != NULL) {
1604 dvmCallMethodA(ts.self(), (Method*) methodID, newObj, true, &unused, args);
1610 * Returns the class of an object.
1612 * JNI spec says: obj must not be NULL.
1614 static jclass GetObjectClass(JNIEnv* env, jobject jobj) {
1615 ScopedJniThreadState ts(env);
1617 assert(jobj != NULL);
1619 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1620 return (jclass) addLocalReference(ts.self(), (Object*) obj->clazz);
1624 * Determine whether "obj" is an instance of "clazz".
1626 static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass jclazz) {
1627 ScopedJniThreadState ts(env);
1629 assert(jclazz != NULL);
1634 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1635 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1636 return dvmInstanceof(obj->clazz, clazz);
1640 * Get a method ID for an instance method.
1642 * While Dalvik bytecode has distinct instructions for virtual, super,
1643 * static, direct, and interface method invocation, JNI only provides
1644 * two functions for acquiring a method ID. This call handles everything
1645 * but static methods.
1647 * JNI defines <init> as an instance method, but Dalvik considers it a
1648 * "direct" method, so we have to special-case it here.
1650 * Dalvik also puts all private methods into the "direct" list, so we
1651 * really need to just search both lists.
1653 static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1654 ScopedJniThreadState ts(env);
1656 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1657 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1658 assert(dvmCheckException(ts.self()));
1659 } else if (dvmIsInterfaceClass(clazz)) {
1660 Method* meth = dvmFindInterfaceMethodHierByDescriptor(clazz, name, sig);
1662 dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
1663 "no method with name='%s' signature='%s' in interface %s",
1664 name, sig, clazz->descriptor);
1666 return (jmethodID) meth;
1668 Method* meth = dvmFindVirtualMethodHierByDescriptor(clazz, name, sig);
1670 /* search private methods and constructors; non-hierarchical */
1671 meth = dvmFindDirectMethodByDescriptor(clazz, name, sig);
1673 if (meth != NULL && dvmIsStaticMethod(meth)) {
1675 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
1676 ALOGD("GetMethodID: not returning static method %s.%s %s",
1677 clazz->descriptor, meth->name, desc);
1683 dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
1684 "no method with name='%s' signature='%s' in class %s",
1685 name, sig, clazz->descriptor);
1688 * The method's class may not be the same as clazz, but if
1689 * it isn't this must be a virtual method and the class must
1690 * be a superclass (and, hence, already initialized).
1692 assert(dvmIsClassInitialized(meth->clazz) || dvmIsClassInitializing(meth->clazz));
1694 return (jmethodID) meth;
1698 * Get a field ID (instance fields).
1700 static jfieldID GetFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1701 ScopedJniThreadState ts(env);
1703 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1705 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1706 assert(dvmCheckException(ts.self()));
1710 jfieldID id = (jfieldID) dvmFindInstanceFieldHier(clazz, name, sig);
1712 dvmThrowExceptionFmt(gDvm.exNoSuchFieldError,
1713 "no field with name='%s' signature='%s' in class %s",
1714 name, sig, clazz->descriptor);
1720 * Get the method ID for a static method in a class.
1722 static jmethodID GetStaticMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1723 ScopedJniThreadState ts(env);
1725 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1726 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1727 assert(dvmCheckException(ts.self()));
1731 Method* meth = dvmFindDirectMethodHierByDescriptor(clazz, name, sig);
1733 /* make sure it's static, not virtual+private */
1734 if (meth != NULL && !dvmIsStaticMethod(meth)) {
1736 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
1737 ALOGD("GetStaticMethodID: not returning nonstatic method %s.%s %s",
1738 clazz->descriptor, meth->name, desc);
1744 jmethodID id = (jmethodID) meth;
1746 dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
1747 "no static method with name='%s' signature='%s' in class %s",
1748 name, sig, clazz->descriptor);
1754 * Get a field ID (static fields).
1756 static jfieldID GetStaticFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1757 ScopedJniThreadState ts(env);
1759 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1760 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1761 assert(dvmCheckException(ts.self()));
1765 jfieldID id = (jfieldID) dvmFindStaticFieldHier(clazz, name, sig);
1767 dvmThrowExceptionFmt(gDvm.exNoSuchFieldError,
1768 "no static field with name='%s' signature='%s' in class %s",
1769 name, sig, clazz->descriptor);
1775 * Get a static field.
1777 * If we get an object reference, add it to the local refs list.
1779 #define GET_STATIC_TYPE_FIELD(_ctype, _jname, _isref) \
1780 static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass jclazz, \
1783 UNUSED_PARAMETER(jclazz); \
1784 ScopedJniThreadState ts(env); \
1785 StaticField* sfield = (StaticField*) fieldID; \
1787 if (dvmIsVolatileField(sfield)) { \
1788 if (_isref) { /* only when _ctype==jobject */ \
1789 Object* obj = dvmGetStaticFieldObjectVolatile(sfield); \
1790 value = (_ctype)(u4)addLocalReference(ts.self(), obj); \
1792 value = (_ctype) dvmGetStaticField##_jname##Volatile(sfield);\
1796 Object* obj = dvmGetStaticFieldObject(sfield); \
1797 value = (_ctype)(u4)addLocalReference(ts.self(), obj); \
1799 value = (_ctype) dvmGetStaticField##_jname(sfield); \
1804 GET_STATIC_TYPE_FIELD(jobject, Object, true);
1805 GET_STATIC_TYPE_FIELD(jboolean, Boolean, false);
1806 GET_STATIC_TYPE_FIELD(jbyte, Byte, false);
1807 GET_STATIC_TYPE_FIELD(jchar, Char, false);
1808 GET_STATIC_TYPE_FIELD(jshort, Short, false);
1809 GET_STATIC_TYPE_FIELD(jint, Int, false);
1810 GET_STATIC_TYPE_FIELD(jlong, Long, false);
1811 GET_STATIC_TYPE_FIELD(jfloat, Float, false);
1812 GET_STATIC_TYPE_FIELD(jdouble, Double, false);
1815 * Set a static field.
1817 #define SET_STATIC_TYPE_FIELD(_ctype, _ctype2, _jname, _isref) \
1818 static void SetStatic##_jname##Field(JNIEnv* env, jclass jclazz, \
1819 jfieldID fieldID, _ctype value) \
1821 UNUSED_PARAMETER(jclazz); \
1822 ScopedJniThreadState ts(env); \
1823 StaticField* sfield = (StaticField*) fieldID; \
1824 if (dvmIsVolatileField(sfield)) { \
1825 if (_isref) { /* only when _ctype==jobject */ \
1826 Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1827 dvmSetStaticFieldObjectVolatile(sfield, valObj); \
1829 dvmSetStaticField##_jname##Volatile(sfield, (_ctype2)value);\
1833 Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1834 dvmSetStaticFieldObject(sfield, valObj); \
1836 dvmSetStaticField##_jname(sfield, (_ctype2)value); \
1840 SET_STATIC_TYPE_FIELD(jobject, Object*, Object, true);
1841 SET_STATIC_TYPE_FIELD(jboolean, bool, Boolean, false);
1842 SET_STATIC_TYPE_FIELD(jbyte, s1, Byte, false);
1843 SET_STATIC_TYPE_FIELD(jchar, u2, Char, false);
1844 SET_STATIC_TYPE_FIELD(jshort, s2, Short, false);
1845 SET_STATIC_TYPE_FIELD(jint, s4, Int, false);
1846 SET_STATIC_TYPE_FIELD(jlong, s8, Long, false);
1847 SET_STATIC_TYPE_FIELD(jfloat, float, Float, false);
1848 SET_STATIC_TYPE_FIELD(jdouble, double, Double, false);
1851 * Get an instance field.
1853 * If we get an object reference, add it to the local refs list.
1855 #define GET_TYPE_FIELD(_ctype, _jname, _isref) \
1856 static _ctype Get##_jname##Field(JNIEnv* env, jobject jobj, \
1859 ScopedJniThreadState ts(env); \
1860 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1861 InstField* field = (InstField*) fieldID; \
1863 if (dvmIsVolatileField(field)) { \
1864 if (_isref) { /* only when _ctype==jobject */ \
1866 dvmGetFieldObjectVolatile(obj, field->byteOffset); \
1867 value = (_ctype)(u4)addLocalReference(ts.self(), valObj); \
1870 dvmGetField##_jname##Volatile(obj, field->byteOffset); \
1874 Object* valObj = dvmGetFieldObject(obj, field->byteOffset); \
1875 value = (_ctype)(u4)addLocalReference(ts.self(), valObj); \
1877 value = (_ctype) dvmGetField##_jname(obj, field->byteOffset);\
1882 GET_TYPE_FIELD(jobject, Object, true);
1883 GET_TYPE_FIELD(jboolean, Boolean, false);
1884 GET_TYPE_FIELD(jbyte, Byte, false);
1885 GET_TYPE_FIELD(jchar, Char, false);
1886 GET_TYPE_FIELD(jshort, Short, false);
1887 GET_TYPE_FIELD(jint, Int, false);
1888 GET_TYPE_FIELD(jlong, Long, false);
1889 GET_TYPE_FIELD(jfloat, Float, false);
1890 GET_TYPE_FIELD(jdouble, Double, false);
1893 * Set an instance field.
1895 #define SET_TYPE_FIELD(_ctype, _ctype2, _jname, _isref) \
1896 static void Set##_jname##Field(JNIEnv* env, jobject jobj, \
1897 jfieldID fieldID, _ctype value) \
1899 ScopedJniThreadState ts(env); \
1900 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1901 InstField* field = (InstField*) fieldID; \
1902 if (dvmIsVolatileField(field)) { \
1903 if (_isref) { /* only when _ctype==jobject */ \
1904 Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1905 dvmSetFieldObjectVolatile(obj, field->byteOffset, valObj); \
1907 dvmSetField##_jname##Volatile(obj, \
1908 field->byteOffset, (_ctype2)value); \
1912 Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1913 dvmSetFieldObject(obj, field->byteOffset, valObj); \
1915 dvmSetField##_jname(obj, \
1916 field->byteOffset, (_ctype2)value); \
1920 SET_TYPE_FIELD(jobject, Object*, Object, true);
1921 SET_TYPE_FIELD(jboolean, bool, Boolean, false);
1922 SET_TYPE_FIELD(jbyte, s1, Byte, false);
1923 SET_TYPE_FIELD(jchar, u2, Char, false);
1924 SET_TYPE_FIELD(jshort, s2, Short, false);
1925 SET_TYPE_FIELD(jint, s4, Int, false);
1926 SET_TYPE_FIELD(jlong, s8, Long, false);
1927 SET_TYPE_FIELD(jfloat, float, Float, false);
1928 SET_TYPE_FIELD(jdouble, double, Double, false);
1931 * Make a virtual method call.
1933 * Three versions (..., va_list, jvalue[]) for each return type. If we're
1934 * returning an Object, we have to add it to the local references table.
1936 #define CALL_VIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \
1937 static _ctype Call##_jname##Method(JNIEnv* env, jobject jobj, \
1938 jmethodID methodID, ...) \
1940 ScopedJniThreadState ts(env); \
1941 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1942 const Method* meth; \
1945 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
1946 if (meth == NULL) { \
1949 va_start(args, methodID); \
1950 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \
1952 if (_isref && !dvmCheckException(ts.self())) \
1953 result.l = (Object*)addLocalReference(ts.self(), result.l); \
1956 static _ctype Call##_jname##MethodV(JNIEnv* env, jobject jobj, \
1957 jmethodID methodID, va_list args) \
1959 ScopedJniThreadState ts(env); \
1960 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1961 const Method* meth; \
1963 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
1964 if (meth == NULL) { \
1967 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \
1968 if (_isref && !dvmCheckException(ts.self())) \
1969 result.l = (Object*)addLocalReference(ts.self(), result.l); \
1972 static _ctype Call##_jname##MethodA(JNIEnv* env, jobject jobj, \
1973 jmethodID methodID, jvalue* args) \
1975 ScopedJniThreadState ts(env); \
1976 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1977 const Method* meth; \
1979 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
1980 if (meth == NULL) { \
1983 dvmCallMethodA(ts.self(), meth, obj, true, &result, args); \
1984 if (_isref && !dvmCheckException(ts.self())) \
1985 result.l = (Object*)addLocalReference(ts.self(), result.l); \
1988 CALL_VIRTUAL(jobject, Object, NULL, (jobject) result.l, true);
1989 CALL_VIRTUAL(jboolean, Boolean, 0, result.z, false);
1990 CALL_VIRTUAL(jbyte, Byte, 0, result.b, false);
1991 CALL_VIRTUAL(jchar, Char, 0, result.c, false);
1992 CALL_VIRTUAL(jshort, Short, 0, result.s, false);
1993 CALL_VIRTUAL(jint, Int, 0, result.i, false);
1994 CALL_VIRTUAL(jlong, Long, 0, result.j, false);
1995 CALL_VIRTUAL(jfloat, Float, 0.0f, result.f, false);
1996 CALL_VIRTUAL(jdouble, Double, 0.0, result.d, false);
1997 CALL_VIRTUAL(void, Void, , , false);
2000 * Make a "non-virtual" method call. We're still calling a virtual method,
2001 * but this time we're not doing an indirection through the object's vtable.
2002 * The "clazz" parameter defines which implementation of a method we want.
2004 * Three versions (..., va_list, jvalue[]) for each return type.
2006 #define CALL_NONVIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \
2007 static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, jobject jobj, \
2008 jclass jclazz, jmethodID methodID, ...) \
2010 ScopedJniThreadState ts(env); \
2011 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
2012 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz); \
2013 const Method* meth; \
2016 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
2017 if (meth == NULL) { \
2020 va_start(args, methodID); \
2021 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \
2022 if (_isref && !dvmCheckException(ts.self())) \
2023 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2027 static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, jobject jobj,\
2028 jclass jclazz, jmethodID methodID, va_list args) \
2030 ScopedJniThreadState ts(env); \
2031 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
2032 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz); \
2033 const Method* meth; \
2035 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
2036 if (meth == NULL) { \
2039 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \
2040 if (_isref && !dvmCheckException(ts.self())) \
2041 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2044 static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, jobject jobj,\
2045 jclass jclazz, jmethodID methodID, jvalue* args) \
2047 ScopedJniThreadState ts(env); \
2048 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
2049 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz); \
2050 const Method* meth; \
2052 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
2053 if (meth == NULL) { \
2056 dvmCallMethodA(ts.self(), meth, obj, true, &result, args); \
2057 if (_isref && !dvmCheckException(ts.self())) \
2058 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2061 CALL_NONVIRTUAL(jobject, Object, NULL, (jobject) result.l, true);
2062 CALL_NONVIRTUAL(jboolean, Boolean, 0, result.z, false);
2063 CALL_NONVIRTUAL(jbyte, Byte, 0, result.b, false);
2064 CALL_NONVIRTUAL(jchar, Char, 0, result.c, false);
2065 CALL_NONVIRTUAL(jshort, Short, 0, result.s, false);
2066 CALL_NONVIRTUAL(jint, Int, 0, result.i, false);
2067 CALL_NONVIRTUAL(jlong, Long, 0, result.j, false);
2068 CALL_NONVIRTUAL(jfloat, Float, 0.0f, result.f, false);
2069 CALL_NONVIRTUAL(jdouble, Double, 0.0, result.d, false);
2070 CALL_NONVIRTUAL(void, Void, , , false);
2074 * Call a static method.
2076 #define CALL_STATIC(_ctype, _jname, _retfail, _retok, _isref) \
2077 static _ctype CallStatic##_jname##Method(JNIEnv* env, jclass jclazz, \
2078 jmethodID methodID, ...) \
2080 UNUSED_PARAMETER(jclazz); \
2081 ScopedJniThreadState ts(env); \
2084 va_start(args, methodID); \
2085 dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
2087 if (_isref && !dvmCheckException(ts.self())) \
2088 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2091 static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass jclazz, \
2092 jmethodID methodID, va_list args) \
2094 UNUSED_PARAMETER(jclazz); \
2095 ScopedJniThreadState ts(env); \
2097 dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
2098 if (_isref && !dvmCheckException(ts.self())) \
2099 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2102 static _ctype CallStatic##_jname##MethodA(JNIEnv* env, jclass jclazz, \
2103 jmethodID methodID, jvalue* args) \
2105 UNUSED_PARAMETER(jclazz); \
2106 ScopedJniThreadState ts(env); \
2108 dvmCallMethodA(ts.self(), (Method*)methodID, NULL, true, &result, args);\
2109 if (_isref && !dvmCheckException(ts.self())) \
2110 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2113 CALL_STATIC(jobject, Object, NULL, (jobject) result.l, true);
2114 CALL_STATIC(jboolean, Boolean, 0, result.z, false);
2115 CALL_STATIC(jbyte, Byte, 0, result.b, false);
2116 CALL_STATIC(jchar, Char, 0, result.c, false);
2117 CALL_STATIC(jshort, Short, 0, result.s, false);
2118 CALL_STATIC(jint, Int, 0, result.i, false);
2119 CALL_STATIC(jlong, Long, 0, result.j, false);
2120 CALL_STATIC(jfloat, Float, 0.0f, result.f, false);
2121 CALL_STATIC(jdouble, Double, 0.0, result.d, false);
2122 CALL_STATIC(void, Void, , , false);
2125 * Create a new String from Unicode data.
2127 * If "len" is zero, we will return an empty string even if "unicodeChars"
2128 * is NULL. (The JNI spec is vague here.)
2130 static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) {
2131 ScopedJniThreadState ts(env);
2132 StringObject* jstr = dvmCreateStringFromUnicode(unicodeChars, len);
2136 dvmReleaseTrackedAlloc((Object*) jstr, NULL);
2137 return (jstring) addLocalReference(ts.self(), (Object*) jstr);
2141 * Return the length of a String in Unicode character units.
2143 static jsize GetStringLength(JNIEnv* env, jstring jstr) {
2144 ScopedJniThreadState ts(env);
2145 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2146 return strObj->length();
2151 * Get a string's character data.
2153 * The result is guaranteed to be valid until ReleaseStringChars is
2154 * called, which means we have to pin it or return a copy.
2156 static const jchar* GetStringChars(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2157 ScopedJniThreadState ts(env);
2159 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2160 ArrayObject* strChars = strObj->array();
2162 pinPrimitiveArray(strChars);
2164 const u2* data = strObj->chars();
2165 if (isCopy != NULL) {
2166 *isCopy = JNI_FALSE;
2168 return (jchar*) data;
2172 * Release our grip on some characters from a string.
2174 static void ReleaseStringChars(JNIEnv* env, jstring jstr, const jchar* chars) {
2175 ScopedJniThreadState ts(env);
2176 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2177 ArrayObject* strChars = strObj->array();
2178 unpinPrimitiveArray(strChars);
2182 * Create a new java.lang.String object from chars in modified UTF-8 form.
2184 * The spec doesn't say how to handle a NULL string. Popular desktop VMs
2185 * accept it and return a NULL pointer in response.
2187 static jstring NewStringUTF(JNIEnv* env, const char* bytes) {
2188 ScopedJniThreadState ts(env);
2189 if (bytes == NULL) {
2192 /* note newStr could come back NULL on OOM */
2193 StringObject* newStr = dvmCreateStringFromCstr(bytes);
2194 jstring result = (jstring) addLocalReference(ts.self(), (Object*) newStr);
2195 dvmReleaseTrackedAlloc((Object*)newStr, NULL);
2200 * Return the length in bytes of the modified UTF-8 form of the string.
2202 static jsize GetStringUTFLength(JNIEnv* env, jstring jstr) {
2203 ScopedJniThreadState ts(env);
2204 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2205 if (strObj == NULL) {
2206 return 0; // Should we throw something or assert?
2208 return strObj->utfLength();
2212 * Convert "string" to modified UTF-8 and return a pointer. The returned
2213 * value must be released with ReleaseStringUTFChars.
2215 * According to the JNI reference, "Returns a pointer to a UTF-8 string,
2216 * or NULL if the operation fails. Returns NULL if and only if an invocation
2217 * of this function has thrown an exception."
2219 * The behavior here currently follows that of other open-source VMs, which
2220 * quietly return NULL if "string" is NULL. We should consider throwing an
2221 * NPE. (The CheckJNI code blows up if you try to pass in a NULL string,
2222 * which should catch this sort of thing during development.) Certain other
2223 * VMs will crash with a segmentation fault.
2225 static const char* GetStringUTFChars(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2226 ScopedJniThreadState ts(env);
2228 /* this shouldn't happen; throw NPE? */
2231 if (isCopy != NULL) {
2234 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2235 char* newStr = dvmCreateCstrFromString(strObj);
2236 if (newStr == NULL) {
2237 /* assume memory failure */
2238 dvmThrowOutOfMemoryError("native heap string alloc failed");
2244 * Release a string created by GetStringUTFChars().
2246 static void ReleaseStringUTFChars(JNIEnv* env, jstring jstr, const char* utf) {
2247 ScopedJniThreadState ts(env);
2252 * Return the capacity of the array.
2254 static jsize GetArrayLength(JNIEnv* env, jarray jarr) {
2255 ScopedJniThreadState ts(env);
2256 ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2257 return arrObj->length;
2261 * Construct a new array that holds objects from class "elementClass".
2263 static jobjectArray NewObjectArray(JNIEnv* env, jsize length,
2264 jclass jelementClass, jobject jinitialElement)
2266 ScopedJniThreadState ts(env);
2268 if (jelementClass == NULL) {
2269 dvmThrowNullPointerException("JNI NewObjectArray elementClass == NULL");
2273 ClassObject* elemClassObj = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jelementClass);
2274 ClassObject* arrayClass = dvmFindArrayClassForElement(elemClassObj);
2275 ArrayObject* newObj = dvmAllocArrayByClass(arrayClass, length, ALLOC_DEFAULT);
2276 if (newObj == NULL) {
2277 assert(dvmCheckException(ts.self()));
2280 jobjectArray newArray = (jobjectArray) addLocalReference(ts.self(), (Object*) newObj);
2281 dvmReleaseTrackedAlloc((Object*) newObj, NULL);
2284 * Initialize the array.
2286 if (jinitialElement != NULL) {
2287 Object* initialElement = dvmDecodeIndirectRef(ts.self(), jinitialElement);
2288 Object** arrayData = (Object**) (void*) newObj->contents;
2289 for (jsize i = 0; i < length; ++i) {
2290 arrayData[i] = initialElement;
2297 static bool checkArrayElementBounds(ArrayObject* arrayObj, jsize index) {
2298 assert(arrayObj != NULL);
2299 if (index < 0 || index >= (int) arrayObj->length) {
2300 dvmThrowArrayIndexOutOfBoundsException(arrayObj->length, index);
2307 * Get one element of an Object array.
2309 * Add the object to the local references table in case the array goes away.
2311 static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index) {
2312 ScopedJniThreadState ts(env);
2314 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2315 if (!checkArrayElementBounds(arrayObj, index)) {
2319 Object* value = ((Object**) (void*) arrayObj->contents)[index];
2320 return addLocalReference(ts.self(), value);
2324 * Set one element of an Object array.
2326 static void SetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index, jobject jobj) {
2327 ScopedJniThreadState ts(env);
2329 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2330 if (!checkArrayElementBounds(arrayObj, index)) {
2334 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
2336 if (obj != NULL && !dvmCanPutArrayElement(obj->clazz, arrayObj->clazz)) {
2337 ALOGV("Can't put a '%s'(%p) into array type='%s'(%p)",
2338 obj->clazz->descriptor, obj,
2339 arrayObj->clazz->descriptor, arrayObj);
2340 dvmThrowArrayStoreExceptionIncompatibleElement(obj->clazz, arrayObj->clazz);
2344 //ALOGV("JNI: set element %d in array %p to %p", index, array, value);
2346 dvmSetObjectArrayElement(arrayObj, index, obj);
2350 * Create a new array of primitive elements.
2352 #define NEW_PRIMITIVE_ARRAY(_artype, _jname, _typechar) \
2353 static _artype New##_jname##Array(JNIEnv* env, jsize length) { \
2354 ScopedJniThreadState ts(env); \
2355 ArrayObject* arrayObj = dvmAllocPrimitiveArray(_typechar, length, ALLOC_DEFAULT); \
2356 if (arrayObj == NULL) { \
2359 _artype result = (_artype) addLocalReference(ts.self(), (Object*) arrayObj); \
2360 dvmReleaseTrackedAlloc((Object*) arrayObj, NULL); \
2363 NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean, 'Z');
2364 NEW_PRIMITIVE_ARRAY(jbyteArray, Byte, 'B');
2365 NEW_PRIMITIVE_ARRAY(jcharArray, Char, 'C');
2366 NEW_PRIMITIVE_ARRAY(jshortArray, Short, 'S');
2367 NEW_PRIMITIVE_ARRAY(jintArray, Int, 'I');
2368 NEW_PRIMITIVE_ARRAY(jlongArray, Long, 'J');
2369 NEW_PRIMITIVE_ARRAY(jfloatArray, Float, 'F');
2370 NEW_PRIMITIVE_ARRAY(jdoubleArray, Double, 'D');
2373 * Get a pointer to a C array of primitive elements from an array object
2374 * of the matching type.
2376 * In a compacting GC, we either need to return a copy of the elements or
2377 * "pin" the memory. Otherwise we run the risk of native code using the
2378 * buffer as the destination of e.g. a blocking read() call that wakes up
2381 #define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
2382 static _ctype* Get##_jname##ArrayElements(JNIEnv* env, \
2383 _ctype##Array jarr, jboolean* isCopy) \
2385 ScopedJniThreadState ts(env); \
2386 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2387 pinPrimitiveArray(arrayObj); \
2388 _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2389 if (isCopy != NULL) { \
2390 *isCopy = JNI_FALSE; \
2396 * Release the storage locked down by the "get" function.
2398 * The spec says, "'mode' has no effect if 'elems' is not a copy of the
2399 * elements in 'array'." They apparently did not anticipate the need to
2402 #define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
2403 static void Release##_jname##ArrayElements(JNIEnv* env, \
2404 _ctype##Array jarr, _ctype* elems, jint mode) \
2406 UNUSED_PARAMETER(elems); \
2407 if (mode != JNI_COMMIT) { \
2408 ScopedJniThreadState ts(env); \
2409 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2410 unpinPrimitiveArray(arrayObj); \
2414 static void throwArrayRegionOutOfBounds(ArrayObject* arrayObj, jsize start,
2415 jsize len, const char* arrayIdentifier)
2417 dvmThrowExceptionFmt(gDvm.exArrayIndexOutOfBoundsException,
2418 "%s offset=%d length=%d %s.length=%d",
2419 arrayObj->clazz->descriptor, start, len, arrayIdentifier,
2424 * Copy a section of a primitive array to a buffer.
2426 #define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
2427 static void Get##_jname##ArrayRegion(JNIEnv* env, \
2428 _ctype##Array jarr, jsize start, jsize len, _ctype* buf) \
2430 ScopedJniThreadState ts(env); \
2431 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2432 _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2433 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
2434 throwArrayRegionOutOfBounds(arrayObj, start, len, "src"); \
2436 memcpy(buf, data + start, len * sizeof(_ctype)); \
2441 * Copy a section of a primitive array from a buffer.
2443 #define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
2444 static void Set##_jname##ArrayRegion(JNIEnv* env, \
2445 _ctype##Array jarr, jsize start, jsize len, const _ctype* buf) \
2447 ScopedJniThreadState ts(env); \
2448 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2449 _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2450 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
2451 throwArrayRegionOutOfBounds(arrayObj, start, len, "dst"); \
2453 memcpy(data + start, buf, len * sizeof(_ctype)); \
2459 * Get<Type>ArrayElements
2460 * Release<Type>ArrayElements
2461 * Get<Type>ArrayRegion
2462 * Set<Type>ArrayRegion
2464 #define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname) \
2465 GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
2466 RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
2467 GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \
2468 SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
2470 PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean);
2471 PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte);
2472 PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char);
2473 PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short);
2474 PRIMITIVE_ARRAY_FUNCTIONS(jint, Int);
2475 PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long);
2476 PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float);
2477 PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double);
2480 * Register one or more native functions in one class.
2482 * This can be called multiple times on the same method, allowing the
2483 * caller to redefine the method implementation at will.
2485 static jint RegisterNatives(JNIEnv* env, jclass jclazz,
2486 const JNINativeMethod* methods, jint nMethods)
2488 ScopedJniThreadState ts(env);
2490 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
2492 if (gDvm.verboseJni) {
2493 ALOGI("[Registering JNI native methods for class %s]",
2497 for (int i = 0; i < nMethods; i++) {
2498 if (!dvmRegisterJNIMethod(clazz, methods[i].name,
2499 methods[i].signature, methods[i].fnPtr))
2508 * Un-register all native methods associated with the class.
2510 * The JNI docs refer to this as a way to reload/relink native libraries,
2511 * and say it "should not be used in normal native code". In particular,
2512 * there is no need to do this during shutdown, and you do not need to do
2513 * this before redefining a method implementation with RegisterNatives.
2515 * It's chiefly useful for a native "plugin"-style library that wasn't
2516 * loaded with System.loadLibrary() (since there's no way to unload those).
2517 * For example, the library could upgrade itself by:
2519 * 1. call UnregisterNatives to unbind the old methods
2520 * 2. ensure that no code is still executing inside it (somehow)
2521 * 3. dlclose() the library
2522 * 4. dlopen() the new library
2523 * 5. use RegisterNatives to bind the methods from the new library
2525 * The above can work correctly without the UnregisterNatives call, but
2526 * creates a window of opportunity in which somebody might try to call a
2527 * method that is pointing at unmapped memory, crashing the VM. In theory
2528 * the same guards that prevent dlclose() from unmapping executing code could
2529 * prevent that anyway, but with this we can be more thorough and also deal
2530 * with methods that only exist in the old or new form of the library (maybe
2531 * the lib wants to try the call and catch the UnsatisfiedLinkError).
2533 static jint UnregisterNatives(JNIEnv* env, jclass jclazz) {
2534 ScopedJniThreadState ts(env);
2536 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
2537 if (gDvm.verboseJni) {
2538 ALOGI("[Unregistering JNI native methods for class %s]",
2541 dvmUnregisterJNINativeMethods(clazz);
2548 * We have to track all monitor enters and exits, so that we can undo any
2549 * outstanding synchronization before the thread exits.
2551 static jint MonitorEnter(JNIEnv* env, jobject jobj) {
2552 ScopedJniThreadState ts(env);
2553 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
2554 dvmLockObject(ts.self(), obj);
2555 trackMonitorEnter(ts.self(), obj);
2560 * Unlock the monitor.
2562 * Throws an IllegalMonitorStateException if the current thread
2563 * doesn't own the monitor. (dvmUnlockObject() takes care of the throw.)
2565 * According to the 1.6 spec, it's legal to call here with an exception
2566 * pending. If this fails, we'll stomp the original exception.
2568 static jint MonitorExit(JNIEnv* env, jobject jobj) {
2569 ScopedJniThreadState ts(env);
2570 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
2571 bool success = dvmUnlockObject(ts.self(), obj);
2573 trackMonitorExit(ts.self(), obj);
2575 return success ? JNI_OK : JNI_ERR;
2579 * Return the JavaVM interface associated with the current thread.
2581 static jint GetJavaVM(JNIEnv* env, JavaVM** vm) {
2582 ScopedJniThreadState ts(env);
2583 *vm = gDvmJni.jniVm;
2584 return (*vm == NULL) ? JNI_ERR : JNI_OK;
2588 * Copies "len" Unicode characters, from offset "start".
2590 static void GetStringRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, jchar* buf) {
2591 ScopedJniThreadState ts(env);
2592 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2593 int strLen = strObj->length();
2594 if (((start|len) < 0) || (start + len > strLen)) {
2595 dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
2598 memcpy(buf, strObj->chars() + start, len * sizeof(u2));
2602 * Translates "len" Unicode characters, from offset "start", into
2603 * modified UTF-8 encoding.
2605 static void GetStringUTFRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, char* buf) {
2606 ScopedJniThreadState ts(env);
2607 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2608 int strLen = strObj->length();
2609 if (((start|len) < 0) || (start + len > strLen)) {
2610 dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
2613 dvmGetStringUtfRegion(strObj, start, len, buf);
2617 * Get a raw pointer to array data.
2619 * The caller is expected to call "release" before doing any JNI calls
2620 * or blocking I/O operations.
2622 * We need to pin the memory or block GC.
2624 static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray jarr, jboolean* isCopy) {
2625 ScopedJniThreadState ts(env);
2626 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2627 pinPrimitiveArray(arrayObj);
2628 void* data = arrayObj->contents;
2629 if (UNLIKELY(isCopy != NULL)) {
2630 *isCopy = JNI_FALSE;
2636 * Release an array obtained with GetPrimitiveArrayCritical.
2638 static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray jarr, void* carray, jint mode) {
2639 if (mode != JNI_COMMIT) {
2640 ScopedJniThreadState ts(env);
2641 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2642 unpinPrimitiveArray(arrayObj);
2647 * Like GetStringChars, but with restricted use.
2649 static const jchar* GetStringCritical(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2650 ScopedJniThreadState ts(env);
2652 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2653 ArrayObject* strChars = strObj->array();
2655 pinPrimitiveArray(strChars);
2657 const u2* data = strObj->chars();
2658 if (isCopy != NULL) {
2659 *isCopy = JNI_FALSE;
2661 return (jchar*) data;
2665 * Like ReleaseStringChars, but with restricted use.
2667 static void ReleaseStringCritical(JNIEnv* env, jstring jstr, const jchar* carray) {
2668 ScopedJniThreadState ts(env);
2669 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2670 ArrayObject* strChars = strObj->array();
2671 unpinPrimitiveArray(strChars);
2675 * Create a new weak global reference.
2677 static jweak NewWeakGlobalRef(JNIEnv* env, jobject jobj) {
2678 ScopedJniThreadState ts(env);
2679 Object *obj = dvmDecodeIndirectRef(ts.self(), jobj);
2680 return (jweak) addWeakGlobalReference(obj);
2684 * Delete the specified weak global reference.
2686 static void DeleteWeakGlobalRef(JNIEnv* env, jweak wref) {
2687 ScopedJniThreadState ts(env);
2688 deleteWeakGlobalReference(wref);
2692 * Quick check for pending exceptions.
2694 * TODO: we should be able to skip the enter/exit macros here.
2696 static jboolean ExceptionCheck(JNIEnv* env) {
2697 ScopedJniThreadState ts(env);
2698 return dvmCheckException(ts.self());
2702 * Returns the type of the object referred to by "obj". It can be local,
2703 * global, or weak global.
2705 * In the current implementation, references can be global and local at
2706 * the same time, so while the return value is accurate it may not tell
2709 static jobjectRefType GetObjectRefType(JNIEnv* env, jobject jobj) {
2710 ScopedJniThreadState ts(env);
2711 return dvmGetJNIRefType(ts.self(), jobj);
2715 * Allocate and return a new java.nio.ByteBuffer for this block of memory.
2717 static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
2718 ScopedJniThreadState ts(env);
2721 ALOGE("JNI ERROR (app bug): negative buffer capacity: %lld", capacity);
2724 if (address == NULL && capacity != 0) {
2725 ALOGE("JNI ERROR (app bug): non-zero capacity for NULL pointer: %lld", capacity);
2729 /* create an instance of java.nio.ReadWriteDirectByteBuffer */
2730 ClassObject* bufferClazz = gDvm.classJavaNioReadWriteDirectByteBuffer;
2731 if (!dvmIsClassInitialized(bufferClazz) && !dvmInitClass(bufferClazz)) {
2734 Object* newObj = dvmAllocObject(bufferClazz, ALLOC_DONT_TRACK);
2735 if (newObj == NULL) {
2738 /* call the constructor */
2739 jobject result = addLocalReference(ts.self(), newObj);
2741 dvmCallMethod(ts.self(), gDvm.methJavaNioReadWriteDirectByteBuffer_init,
2742 newObj, &unused, (jint) address, (jint) capacity);
2743 if (dvmGetException(ts.self()) != NULL) {
2744 deleteLocalReference(ts.self(), result);
2751 * Get the starting address of the buffer for the specified java.nio.Buffer.
2753 * If this is not a "direct" buffer, we return NULL.
2755 static void* GetDirectBufferAddress(JNIEnv* env, jobject jbuf) {
2756 ScopedJniThreadState ts(env);
2758 // All Buffer objects have an effectiveDirectAddress field.
2759 Object* bufObj = dvmDecodeIndirectRef(ts.self(), jbuf);
2760 return (void*) dvmGetFieldInt(bufObj, gDvm.offJavaNioBuffer_effectiveDirectAddress);
2764 * Get the capacity of the buffer for the specified java.nio.Buffer.
2766 * Returns -1 if the object is not a direct buffer. (We actually skip
2767 * this check, since it's expensive to determine, and just return the
2768 * capacity regardless.)
2770 static jlong GetDirectBufferCapacity(JNIEnv* env, jobject jbuf) {
2771 ScopedJniThreadState ts(env);
2774 * The capacity is always in the Buffer.capacity field.
2776 * (The "check" version should verify that this is actually a Buffer,
2777 * but we're not required to do so here.)
2779 Object* buf = dvmDecodeIndirectRef(ts.self(), jbuf);
2780 return dvmGetFieldInt(buf, gDvm.offJavaNioBuffer_capacity);
2785 * ===========================================================================
2786 * JNI invocation functions
2787 * ===========================================================================
2791 * Handle AttachCurrentThread{AsDaemon}.
2793 * We need to make sure the VM is actually running. For example, if we start
2794 * up, issue an Attach, and the VM exits almost immediately, by the time the
2795 * attaching happens the VM could already be shutting down.
2797 * It's hard to avoid a race condition here because we don't want to hold
2798 * a lock across the entire operation. What we can do is temporarily
2799 * increment the thread count to prevent a VM exit.
2801 * This could potentially still have problems if a daemon thread calls here
2802 * while the VM is shutting down. dvmThreadSelf() will work, since it just
2803 * uses pthread TLS, but dereferencing "vm" could fail. Such is life when
2804 * you shut down a VM while threads are still running inside it.
2806 * Remember that some code may call this as a way to find the per-thread
2807 * JNIEnv pointer. Don't do excess work for that case.
2809 static jint attachThread(JavaVM* vm, JNIEnv** p_env, void* thr_args, bool isDaemon) {
2810 JavaVMAttachArgs* args = (JavaVMAttachArgs*) thr_args;
2813 * Return immediately if we're already one with the VM.
2815 Thread* self = dvmThreadSelf();
2817 *p_env = self->jniEnv;
2822 * No threads allowed in zygote mode.
2828 /* increment the count to keep the VM from bailing while we run */
2829 dvmLockThreadList(NULL);
2830 if (gDvm.nonDaemonThreadCount == 0) {
2832 ALOGV("Refusing to attach thread '%s' -- VM is shutting down",
2833 (thr_args == NULL) ? "(unknown)" : args->name);
2834 dvmUnlockThreadList();
2837 gDvm.nonDaemonThreadCount++;
2838 dvmUnlockThreadList();
2840 /* tweak the JavaVMAttachArgs as needed */
2841 JavaVMAttachArgs argsCopy;
2843 /* allow the v1.1 calling convention */
2844 argsCopy.version = JNI_VERSION_1_2;
2845 argsCopy.name = NULL;
2846 argsCopy.group = (jobject) dvmGetMainThreadGroup();
2848 assert(args->version >= JNI_VERSION_1_2);
2850 argsCopy.version = args->version;
2851 argsCopy.name = args->name;
2852 if (args->group != NULL) {
2853 argsCopy.group = (jobject) dvmDecodeIndirectRef(NULL, args->group);
2855 argsCopy.group = (jobject) dvmGetMainThreadGroup();
2859 bool result = dvmAttachCurrentThread(&argsCopy, isDaemon);
2861 /* restore the count */
2862 dvmLockThreadList(NULL);
2863 gDvm.nonDaemonThreadCount--;
2864 dvmUnlockThreadList();
2867 * Change the status to indicate that we're out in native code. This
2868 * call is not guarded with state-change macros, so we have to do it
2872 self = dvmThreadSelf();
2873 assert(self != NULL);
2874 dvmChangeStatus(self, THREAD_NATIVE);
2875 *p_env = self->jniEnv;
2883 * Attach the current thread to the VM. If the thread is already attached,
2886 static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
2887 return attachThread(vm, p_env, thr_args, false);
2891 * Like AttachCurrentThread, but set the "daemon" flag.
2893 static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args)
2895 return attachThread(vm, p_env, thr_args, true);
2899 * Dissociate the current thread from the VM.
2901 static jint DetachCurrentThread(JavaVM* vm) {
2902 Thread* self = dvmThreadSelf();
2904 /* not attached, can't do anything */
2908 /* switch to "running" to check for suspension */
2909 dvmChangeStatus(self, THREAD_RUNNING);
2911 /* detach the thread */
2912 dvmDetachCurrentThread();
2914 /* (no need to change status back -- we have no status) */
2919 * If current thread is attached to VM, return the associated JNIEnv.
2920 * Otherwise, stuff NULL in and return JNI_EDETACHED.
2922 * JVMTI overloads this by specifying a magic value for "version", so we
2923 * do want to check that here.
2925 static jint GetEnv(JavaVM* vm, void** env, jint version) {
2926 Thread* self = dvmThreadSelf();
2928 if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6) {
2929 return JNI_EVERSION;
2935 /* TODO: status change is probably unnecessary */
2936 dvmChangeStatus(self, THREAD_RUNNING);
2937 *env = (void*) dvmGetThreadJNIEnv(self);
2938 dvmChangeStatus(self, THREAD_NATIVE);
2940 return (*env != NULL) ? JNI_OK : JNI_EDETACHED;
2944 * Destroy the VM. This may be called from any thread.
2946 * If the current thread is attached, wait until the current thread is
2947 * the only non-daemon user-level thread. If the current thread is not
2948 * attached, we attach it and do the processing as usual. (If the attach
2949 * fails, it's probably because all the non-daemon threads have already
2950 * exited and the VM doesn't want to let us back in.)
2952 * TODO: we don't really deal with the situation where more than one thread
2953 * has called here. One thread wins, the other stays trapped waiting on
2954 * the condition variable forever. Not sure this situation is interesting
2957 static jint DestroyJavaVM(JavaVM* vm) {
2958 JavaVMExt* ext = (JavaVMExt*) vm;
2963 if (gDvm.verboseShutdown) {
2964 ALOGD("DestroyJavaVM waiting for non-daemon threads to exit");
2968 * Sleep on a condition variable until it's okay to exit.
2970 Thread* self = dvmThreadSelf();
2973 if (AttachCurrentThread(vm, &tmpEnv, NULL) != JNI_OK) {
2974 ALOGV("Unable to reattach main for Destroy; assuming VM is shutting down (count=%d)",
2975 gDvm.nonDaemonThreadCount);
2978 ALOGV("Attached to wait for shutdown in Destroy");
2981 dvmChangeStatus(self, THREAD_VMWAIT);
2983 dvmLockThreadList(self);
2984 gDvm.nonDaemonThreadCount--; // remove current thread from count
2986 while (gDvm.nonDaemonThreadCount > 0) {
2987 pthread_cond_wait(&gDvm.vmExitCond, &gDvm.threadListLock);
2990 dvmUnlockThreadList();
2994 // TODO: call System.exit() to run any registered shutdown hooks
2995 // (this may not return -- figure out how this should work)
2997 if (gDvm.verboseShutdown) {
2998 ALOGD("DestroyJavaVM shutting VM down");
3002 // TODO - free resources associated with JNI-attached daemon threads
3011 * ===========================================================================
3013 * ===========================================================================
3016 static const struct JNINativeInterface gNativeInterface = {
3027 FromReflectedMethod,
3051 EnsureLocalCapacity,
3094 CallNonvirtualObjectMethod,
3095 CallNonvirtualObjectMethodV,
3096 CallNonvirtualObjectMethodA,
3097 CallNonvirtualBooleanMethod,
3098 CallNonvirtualBooleanMethodV,
3099 CallNonvirtualBooleanMethodA,
3100 CallNonvirtualByteMethod,
3101 CallNonvirtualByteMethodV,
3102 CallNonvirtualByteMethodA,
3103 CallNonvirtualCharMethod,
3104 CallNonvirtualCharMethodV,
3105 CallNonvirtualCharMethodA,
3106 CallNonvirtualShortMethod,
3107 CallNonvirtualShortMethodV,
3108 CallNonvirtualShortMethodA,
3109 CallNonvirtualIntMethod,
3110 CallNonvirtualIntMethodV,
3111 CallNonvirtualIntMethodA,
3112 CallNonvirtualLongMethod,
3113 CallNonvirtualLongMethodV,
3114 CallNonvirtualLongMethodA,
3115 CallNonvirtualFloatMethod,
3116 CallNonvirtualFloatMethodV,
3117 CallNonvirtualFloatMethodA,
3118 CallNonvirtualDoubleMethod,
3119 CallNonvirtualDoubleMethodV,
3120 CallNonvirtualDoubleMethodA,
3121 CallNonvirtualVoidMethod,
3122 CallNonvirtualVoidMethodV,
3123 CallNonvirtualVoidMethodA,
3148 CallStaticObjectMethod,
3149 CallStaticObjectMethodV,
3150 CallStaticObjectMethodA,
3151 CallStaticBooleanMethod,
3152 CallStaticBooleanMethodV,
3153 CallStaticBooleanMethodA,
3154 CallStaticByteMethod,
3155 CallStaticByteMethodV,
3156 CallStaticByteMethodA,
3157 CallStaticCharMethod,
3158 CallStaticCharMethodV,
3159 CallStaticCharMethodA,
3160 CallStaticShortMethod,
3161 CallStaticShortMethodV,
3162 CallStaticShortMethodA,
3163 CallStaticIntMethod,
3164 CallStaticIntMethodV,
3165 CallStaticIntMethodA,
3166 CallStaticLongMethod,
3167 CallStaticLongMethodV,
3168 CallStaticLongMethodA,
3169 CallStaticFloatMethod,
3170 CallStaticFloatMethodV,
3171 CallStaticFloatMethodA,
3172 CallStaticDoubleMethod,
3173 CallStaticDoubleMethodV,
3174 CallStaticDoubleMethodA,
3175 CallStaticVoidMethod,
3176 CallStaticVoidMethodV,
3177 CallStaticVoidMethodA,
3181 GetStaticObjectField,
3182 GetStaticBooleanField,
3185 GetStaticShortField,
3188 GetStaticFloatField,
3189 GetStaticDoubleField,
3191 SetStaticObjectField,
3192 SetStaticBooleanField,
3195 SetStaticShortField,
3198 SetStaticFloatField,
3199 SetStaticDoubleField,
3210 ReleaseStringUTFChars,
3214 GetObjectArrayElement,
3215 SetObjectArrayElement,
3226 GetBooleanArrayElements,
3227 GetByteArrayElements,
3228 GetCharArrayElements,
3229 GetShortArrayElements,
3230 GetIntArrayElements,
3231 GetLongArrayElements,
3232 GetFloatArrayElements,
3233 GetDoubleArrayElements,
3235 ReleaseBooleanArrayElements,
3236 ReleaseByteArrayElements,
3237 ReleaseCharArrayElements,
3238 ReleaseShortArrayElements,
3239 ReleaseIntArrayElements,
3240 ReleaseLongArrayElements,
3241 ReleaseFloatArrayElements,
3242 ReleaseDoubleArrayElements,
3244 GetBooleanArrayRegion,
3247 GetShortArrayRegion,
3250 GetFloatArrayRegion,
3251 GetDoubleArrayRegion,
3252 SetBooleanArrayRegion,
3255 SetShortArrayRegion,
3258 SetFloatArrayRegion,
3259 SetDoubleArrayRegion,
3272 GetPrimitiveArrayCritical,
3273 ReleasePrimitiveArrayCritical,
3276 ReleaseStringCritical,
3279 DeleteWeakGlobalRef,
3283 NewDirectByteBuffer,
3284 GetDirectBufferAddress,
3285 GetDirectBufferCapacity,
3290 static const struct JNIInvokeInterface gInvokeInterface = {
3296 AttachCurrentThread,
3297 DetachCurrentThread,
3301 AttachCurrentThreadAsDaemon,
3305 * ===========================================================================
3307 * ===========================================================================
3311 * Create a new JNIEnv struct and add it to the VM's list.
3313 * "self" will be NULL for the main thread, since the VM hasn't started
3314 * yet; the value will be filled in later.
3316 JNIEnv* dvmCreateJNIEnv(Thread* self) {
3317 JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
3320 // ALOGI("Ent CreateJNIEnv: threadid=%d %p", self->threadId, self);
3324 JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
3325 newEnv->funcTable = &gNativeInterface;
3327 dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
3328 assert(newEnv->envThreadId != 0);
3330 /* make it obvious if we fail to initialize these later */
3331 newEnv->envThreadId = 0x77777775;
3332 newEnv->self = (Thread*) 0x77777779;
3334 if (gDvmJni.useCheckJni) {
3335 dvmUseCheckedJniEnv(newEnv);
3338 ScopedPthreadMutexLock lock(&vm->envListLock);
3340 /* insert at head of list */
3341 newEnv->next = vm->envList;
3342 assert(newEnv->prev == NULL);
3343 if (vm->envList == NULL) {
3344 // rare, but possible
3345 vm->envList = newEnv;
3347 vm->envList->prev = newEnv;
3349 vm->envList = newEnv;
3352 // ALOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self);
3353 return (JNIEnv*) newEnv;
3357 * Remove a JNIEnv struct from the list and free it.
3359 void dvmDestroyJNIEnv(JNIEnv* env) {
3364 //ALOGI("Ent DestroyJNIEnv: threadid=%d %p", self->threadId, self);
3366 JNIEnvExt* extEnv = (JNIEnvExt*) env;
3367 JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
3369 ScopedPthreadMutexLock lock(&vm->envListLock);
3371 if (extEnv == vm->envList) {
3372 assert(extEnv->prev == NULL);
3373 vm->envList = extEnv->next;
3375 assert(extEnv->prev != NULL);
3376 extEnv->prev->next = extEnv->next;
3378 if (extEnv->next != NULL) {
3379 extEnv->next->prev = extEnv->prev;
3383 //ALOGI("Xit DestroyJNIEnv: threadid=%d %p", self->threadId, self);
3387 * Enable "checked JNI" after the VM has partially started. This must
3388 * only be called in "zygote" mode, when we have one thread running.
3390 * This doesn't attempt to rewrite the JNI call bridge associated with
3391 * native methods, so we won't get those checks for any methods that have
3392 * already been resolved.
3394 void dvmLateEnableCheckedJni() {
3395 JNIEnvExt* extEnv = dvmGetJNIEnvForThread();
3396 if (extEnv == NULL) {
3397 ALOGE("dvmLateEnableCheckedJni: thread has no JNIEnv");
3400 JavaVMExt* extVm = (JavaVMExt*) gDvmJni.jniVm;
3401 assert(extVm != NULL);
3403 if (!gDvmJni.useCheckJni) {
3404 ALOGD("Late-enabling CheckJNI");
3405 dvmUseCheckedJniVm(extVm);
3406 dvmUseCheckedJniEnv(extEnv);
3408 ALOGD("Not late-enabling CheckJNI (already on)");
3415 jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
3420 * Return a buffer full of created VMs.
3422 * We always have zero or one.
3424 jint JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs) {
3425 if (gDvmJni.jniVm != NULL) {
3428 *vmBuf++ = gDvmJni.jniVm;
3437 * Create a new VM instance.
3439 * The current thread becomes the main VM thread. We return immediately,
3440 * which effectively means the caller is executing in a native method.
3442 jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
3443 const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args;
3444 if (args->version < JNI_VERSION_1_2) {
3445 return JNI_EVERSION;
3448 // TODO: don't allow creation of multiple VMs -- one per customer for now
3450 /* zero globals; not strictly necessary the first time a VM is started */
3451 memset(&gDvm, 0, sizeof(gDvm));
3454 * Set up structures for JNIEnv and VM.
3456 JavaVMExt* pVM = (JavaVMExt*) calloc(1, sizeof(JavaVMExt));
3457 pVM->funcTable = &gInvokeInterface;
3458 pVM->envList = NULL;
3459 dvmInitMutex(&pVM->envListLock);
3461 UniquePtr<const char*[]> argv(new const char*[args->nOptions]);
3462 memset(argv.get(), 0, sizeof(char*) * (args->nOptions));
3465 * Convert JNI args to argv.
3467 * We have to pull out vfprintf/exit/abort, because they use the
3468 * "extraInfo" field to pass function pointer "hooks" in. We also
3469 * look for the -Xcheck:jni stuff here.
3472 for (int i = 0; i < args->nOptions; i++) {
3473 const char* optStr = args->options[i].optionString;
3474 if (optStr == NULL) {
3475 dvmFprintf(stderr, "ERROR: CreateJavaVM failed: argument %d was NULL\n", i);
3477 } else if (strcmp(optStr, "vfprintf") == 0) {
3478 gDvm.vfprintfHook = (int (*)(FILE *, const char*, va_list))args->options[i].extraInfo;
3479 } else if (strcmp(optStr, "exit") == 0) {
3480 gDvm.exitHook = (void (*)(int)) args->options[i].extraInfo;
3481 } else if (strcmp(optStr, "abort") == 0) {
3482 gDvm.abortHook = (void (*)(void))args->options[i].extraInfo;
3483 } else if (strcmp(optStr, "sensitiveThread") == 0) {
3484 gDvm.isSensitiveThreadHook = (bool (*)(void))args->options[i].extraInfo;
3485 } else if (strcmp(optStr, "-Xcheck:jni") == 0) {
3486 gDvmJni.useCheckJni = true;
3487 } else if (strncmp(optStr, "-Xjniopts:", 10) == 0) {
3488 char* jniOpts = strdup(optStr + 10);
3489 size_t jniOptCount = 1;
3490 for (char* p = jniOpts; *p != 0; ++p) {
3496 char* jniOpt = jniOpts;
3497 for (size_t i = 0; i < jniOptCount; ++i) {
3498 if (strcmp(jniOpt, "warnonly") == 0) {
3499 gDvmJni.warnOnly = true;
3500 } else if (strcmp(jniOpt, "forcecopy") == 0) {
3501 gDvmJni.forceCopy = true;
3502 } else if (strcmp(jniOpt, "logThirdPartyJni") == 0) {
3503 gDvmJni.logThirdPartyJni = true;
3505 dvmFprintf(stderr, "ERROR: CreateJavaVM failed: unknown -Xjniopts option '%s'\n",
3509 jniOpt += strlen(jniOpt) + 1;
3513 /* regular option */
3514 argv[argc++] = optStr;
3518 if (gDvmJni.useCheckJni) {
3519 dvmUseCheckedJniVm(pVM);
3522 if (gDvmJni.jniVm != NULL) {
3523 dvmFprintf(stderr, "ERROR: Dalvik only supports one VM per process\n");
3526 gDvmJni.jniVm = (JavaVM*) pVM;
3529 * Create a JNIEnv for the main thread. We need to have something set up
3530 * here because some of the class initialization we do when starting
3531 * up the VM will call into native code.
3533 JNIEnvExt* pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);
3535 /* Initialize VM. */
3536 gDvm.initializing = true;
3537 std::string status =
3538 dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);
3539 gDvm.initializing = false;
3541 if (!status.empty()) {
3544 ALOGW("CreateJavaVM failed: %s", status.c_str());
3549 * Success! Return stuff to caller.
3551 dvmChangeStatus(NULL, THREAD_NATIVE);
3552 *p_env = (JNIEnv*) pEnv;
3553 *p_vm = (JavaVM*) pVM;
3554 ALOGV("CreateJavaVM succeeded");