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"
22 #include "ScopedPthreadMutexLock.h"
23 #include "UniquePtr.h"
30 Native methods and interaction with the GC
32 All JNI methods must start by changing their thread status to
33 THREAD_RUNNING, and finish by changing it back to THREAD_NATIVE before
34 returning to native code. The switch to "running" triggers a thread
37 With a rudimentary GC we should be able to skip the status change for
38 simple functions, e.g. IsSameObject, GetJavaVM, GetStringLength, maybe
39 even access to fields with primitive types. Our options are more limited
42 For performance reasons we do as little error-checking as possible here.
43 For example, we don't check to make sure the correct type of Object is
44 passed in when setting a field, and we don't prevent you from storing
45 new values in a "final" field. Such things are best handled in the
46 "check" version. For actions that are common, dangerous, and must be
47 checked at runtime, such as array bounds checks, we do the tests here.
50 General notes on local/global reference tracking
52 JNI provides explicit control over natively-held references that the GC
53 needs to know about. These can be local, in which case they're released
54 when the native method returns into the VM, or global, which are held
55 until explicitly released. (There are also weak-global references,
56 which have the lifespan and visibility of global references, but the
57 object they refer to may be collected.)
59 The references can be created with explicit JNI NewLocalRef / NewGlobalRef
60 calls. The former is very unusual, the latter is reasonably common
61 (e.g. for caching references to class objects).
63 Local references are most often created as a side-effect of JNI functions.
64 For example, the AllocObject/NewObject functions must create local
65 references to the objects returned, because nothing else in the GC root
66 set has a reference to the new objects.
68 The most common mode of operation is for a method to create zero or
69 more local references and return. Explicit "local delete" operations
70 are expected to be exceedingly rare, except when walking through an
71 object array, and the Push/PopLocalFrame calls are expected to be used
72 infrequently. For efficient operation, we want to add new local refs
73 with a simple store/increment operation; to avoid infinite growth in
74 pathological situations, we need to reclaim the space used by deleted
77 If we just want to maintain a list for the GC root set, we can use an
78 expanding append-only array that compacts when objects are deleted.
79 In typical situations, e.g. running through an array of objects, we will
80 be deleting one of the most recently added entries, so we can minimize
81 the number of elements moved (or avoid having to move any).
83 If we want to conceal the pointer values from native code, which is
84 necessary to allow the GC to move JNI-referenced objects around, then we
85 have to use a more complicated indirection mechanism.
87 The spec says, "Local references are only valid in the thread in which
88 they are created. The native code must not pass local references from
89 one thread to another."
94 For some large chunks of data, notably primitive arrays and String data,
95 JNI allows the VM to choose whether it wants to pin the array object or
96 make a copy. We currently pin the memory for better execution performance.
98 TODO: we're using simple root set references to pin primitive array data,
99 because they have the property we need (i.e. the pointer we return is
100 guaranteed valid until we explicitly release it). However, if we have a
101 compacting GC and don't want to pin all memory held by all global refs,
102 we need to treat these differently.
105 Global reference tracking
107 There should be a small "active" set centered around the most-recently
110 Because it's global, access to it has to be synchronized. Additions and
111 removals require grabbing a mutex. If the table serves as an indirection
112 mechanism (i.e. it's not just a list for the benefit of the garbage
113 collector), reference lookups may also require grabbing a mutex.
115 The JNI spec does not define any sort of limit, so the list must be able
116 to expand to a reasonable size. It may be useful to log significant
117 increases in usage to help identify resource leaks.
120 Weak-global reference tracking
125 Local reference tracking
127 Each Thread/JNIEnv points to an IndirectRefTable.
129 We implement Push/PopLocalFrame with actual stack frames. Before a JNI
130 frame gets popped, we set "nextEntry" to the "top" pointer of the current
131 frame, effectively releasing the references.
133 The GC will scan all references in the table.
137 static void ReportJniError() {
138 dvmDumpThread(dvmThreadSelf(), false);
142 #ifdef WITH_JNI_STACK_CHECK
143 # define COMPUTE_STACK_SUM(_self) computeStackSum(_self);
144 # define CHECK_STACK_SUM(_self) checkStackSum(_self);
147 * Compute a CRC on the entire interpreted stack.
149 * Would be nice to compute it on "self" as well, but there are parts of
150 * the Thread that can be altered by other threads (e.g. prev/next pointers).
152 static void computeStackSum(Thread* self) {
153 const u1* low = (const u1*)SAVEAREA_FROM_FP(self->interpSave.curFrame);
154 u4 crc = dvmInitCrc32();
156 crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
157 self->stackCrc = crc;
161 * Compute a CRC on the entire interpreted stack, and compare it to what
162 * we previously computed.
164 * We can execute JNI directly from native code without calling in from
165 * interpreted code during VM initialization and immediately after JNI
166 * thread attachment. Another opportunity exists during JNI_OnLoad. Rather
167 * than catching these cases we just ignore them here, which is marginally
168 * less accurate but reduces the amount of code we have to touch with #ifdefs.
170 static void checkStackSum(Thread* self) {
171 const u1* low = (const u1*)SAVEAREA_FROM_FP(self->interpSave.curFrame);
172 u4 stackCrc = self->stackCrc;
174 u4 crc = dvmInitCrc32();
175 crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
176 if (crc != stackCrc) {
177 const Method* meth = dvmGetCurrentJNIMethod();
178 if (dvmComputeExactFrameDepth(self->interpSave.curFrame) == 1) {
179 ALOGD("JNI: bad stack CRC (0x%08x) -- okay during init", stackCrc);
180 } else if (strcmp(meth->name, "nativeLoad") == 0 &&
181 (strcmp(meth->clazz->descriptor, "Ljava/lang/Runtime;") == 0)) {
182 ALOGD("JNI: bad stack CRC (0x%08x) -- okay during JNI_OnLoad", stackCrc);
184 ALOGW("JNI: bad stack CRC (%08x vs %08x)", crc, stackCrc);
188 self->stackCrc = (u4) -1; /* make logic errors more noticeable */
192 # define COMPUTE_STACK_SUM(_self) ((void)0)
193 # define CHECK_STACK_SUM(_self) ((void)0)
198 * ===========================================================================
200 * ===========================================================================
204 * Entry/exit processing for all JNI calls.
206 * We skip the (curiously expensive) thread-local storage lookup on our Thread*.
207 * If the caller has passed the wrong JNIEnv in, we're going to be accessing unsynchronized
208 * structures from more than one thread, and things are going to fail
209 * in bizarre ways. This is only sensible if the native code has been
210 * fully exercised with CheckJNI enabled.
212 class ScopedJniThreadState {
214 explicit ScopedJniThreadState(JNIEnv* env) {
215 mSelf = ((JNIEnvExt*) env)->self;
217 if (UNLIKELY(gDvmJni.workAroundAppJniBugs)) {
218 // When emulating direct pointers with indirect references, it's critical
219 // that we use the correct per-thread indirect reference table.
220 Thread* self = gDvmJni.workAroundAppJniBugs ? dvmThreadSelf() : mSelf;
222 ALOGE("JNI ERROR: env->self != thread-self (%p vs. %p); auto-correcting", mSelf, self);
227 CHECK_STACK_SUM(mSelf);
228 dvmChangeStatus(mSelf, THREAD_RUNNING);
231 ~ScopedJniThreadState() {
232 dvmChangeStatus(mSelf, THREAD_NATIVE);
233 COMPUTE_STACK_SUM(mSelf);
236 inline Thread* self() {
243 // Disallow copy and assignment.
244 ScopedJniThreadState(const ScopedJniThreadState&);
245 void operator=(const ScopedJniThreadState&);
248 #define kGlobalRefsTableInitialSize 512
249 #define kGlobalRefsTableMaxSize 51200 /* arbitrary, must be < 64K */
250 #define kGrefWaterInterval 100
251 #define kTrackGrefUsage true
253 #define kWeakGlobalRefsTableInitialSize 16
255 #define kPinTableInitialSize 16
256 #define kPinTableMaxSize 1024
257 #define kPinComplainThreshold 10
259 bool dvmJniStartup() {
260 if (!gDvm.jniGlobalRefTable.init(kGlobalRefsTableInitialSize,
261 kGlobalRefsTableMaxSize,
262 kIndirectKindGlobal)) {
265 if (!gDvm.jniWeakGlobalRefTable.init(kWeakGlobalRefsTableInitialSize,
266 kGlobalRefsTableMaxSize,
267 kIndirectKindWeakGlobal)) {
271 dvmInitMutex(&gDvm.jniGlobalRefLock);
272 dvmInitMutex(&gDvm.jniWeakGlobalRefLock);
273 gDvm.jniGlobalRefLoMark = 0;
274 gDvm.jniGlobalRefHiMark = kGrefWaterInterval * 2;
276 if (!dvmInitReferenceTable(&gDvm.jniPinRefTable, kPinTableInitialSize, kPinTableMaxSize)) {
280 dvmInitMutex(&gDvm.jniPinRefLock);
285 void dvmJniShutdown() {
286 gDvm.jniGlobalRefTable.destroy();
287 gDvm.jniWeakGlobalRefTable.destroy();
288 dvmClearReferenceTable(&gDvm.jniPinRefTable);
292 * Find the JNIEnv associated with the current thread.
294 * Currently stored in the Thread struct. Could also just drop this into
295 * thread-local storage.
297 JNIEnvExt* dvmGetJNIEnvForThread() {
298 Thread* self = dvmThreadSelf();
302 return (JNIEnvExt*) dvmGetThreadJNIEnv(self);
306 * Convert an indirect reference to an Object reference. The indirect
307 * reference may be local, global, or weak-global.
309 * If "jobj" is NULL, or is a weak global reference whose reference has
310 * been cleared, this returns NULL. If jobj is an invalid indirect
311 * reference, kInvalidIndirectRefObject is returned.
313 * Note "env" may be NULL when decoding global references.
315 Object* dvmDecodeIndirectRef(Thread* self, jobject jobj) {
320 switch (indirectRefKind(jobj)) {
321 case kIndirectKindLocal:
323 Object* result = self->jniLocalRefTable.get(jobj);
324 if (UNLIKELY(result == NULL)) {
325 ALOGE("JNI ERROR (app bug): use of deleted local reference (%p)", jobj);
330 case kIndirectKindGlobal:
332 // TODO: find a way to avoid the mutex activity here
333 IndirectRefTable* pRefTable = &gDvm.jniGlobalRefTable;
334 ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
335 Object* result = pRefTable->get(jobj);
336 if (UNLIKELY(result == NULL)) {
337 ALOGE("JNI ERROR (app bug): use of deleted global reference (%p)", jobj);
342 case kIndirectKindWeakGlobal:
344 // TODO: find a way to avoid the mutex activity here
345 IndirectRefTable* pRefTable = &gDvm.jniWeakGlobalRefTable;
346 ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
347 Object* result = pRefTable->get(jobj);
348 if (result == kClearedJniWeakGlobal) {
350 } else if (UNLIKELY(result == NULL)) {
351 ALOGE("JNI ERROR (app bug): use of deleted weak global reference (%p)", jobj);
356 case kIndirectKindInvalid:
358 if (UNLIKELY(gDvmJni.workAroundAppJniBugs)) {
359 // Assume an invalid local reference is actually a direct pointer.
360 return reinterpret_cast<Object*>(jobj);
362 ALOGW("Invalid indirect reference %p in decodeIndirectRef", jobj);
364 return kInvalidIndirectRefObject;
368 static void AddLocalReferenceFailure(IndirectRefTable* pRefTable) {
369 pRefTable->dump("JNI local");
370 ALOGE("Failed adding to JNI local ref table (has %zd entries)", pRefTable->capacity());
371 ReportJniError(); // spec says call FatalError; this is equivalent
375 * Add a local reference for an object to the current stack frame. When
376 * the native function returns, the reference will be discarded.
378 * We need to allow the same reference to be added multiple times.
380 * This will be called on otherwise unreferenced objects. We cannot do
381 * GC allocations here, and it's best if we don't grab a mutex.
383 static inline jobject addLocalReference(Thread* self, Object* obj) {
388 IndirectRefTable* pRefTable = &self->jniLocalRefTable;
389 void* curFrame = self->interpSave.curFrame;
390 u4 cookie = SAVEAREA_FROM_FP(curFrame)->xtra.localRefCookie;
391 jobject jobj = (jobject) pRefTable->add(cookie, obj);
392 if (UNLIKELY(jobj == NULL)) {
393 AddLocalReferenceFailure(pRefTable);
396 if (UNLIKELY(gDvmJni.workAroundAppJniBugs)) {
397 // Hand out direct pointers to support broken old apps.
398 return reinterpret_cast<jobject>(obj);
404 * Ensure that at least "capacity" references can be held in the local
405 * refs table of the current thread.
407 static bool ensureLocalCapacity(Thread* self, int capacity) {
408 int numEntries = self->jniLocalRefTable.capacity();
409 // TODO: this isn't quite right, since "numEntries" includes holes
410 return ((kJniLocalRefMax - numEntries) >= capacity);
414 * Explicitly delete a reference from the local list.
416 static void deleteLocalReference(Thread* self, jobject jobj) {
421 IndirectRefTable* pRefTable = &self->jniLocalRefTable;
422 void* curFrame = self->interpSave.curFrame;
423 u4 cookie = SAVEAREA_FROM_FP(curFrame)->xtra.localRefCookie;
424 if (!pRefTable->remove(cookie, jobj)) {
426 * Attempting to delete a local reference that is not in the
427 * topmost local reference frame is a no-op. DeleteLocalRef returns
428 * void and doesn't throw any exceptions, but we should probably
429 * complain about it so the user will notice that things aren't
430 * going quite the way they expect.
432 ALOGW("JNI WARNING: DeleteLocalRef(%p) failed to find entry", jobj);
437 * Add a global reference for an object.
439 * We may add the same object more than once. Add/remove calls are paired,
440 * so it needs to appear on the list multiple times.
442 static jobject addGlobalReference(Object* obj) {
447 //ALOGI("adding obj=%p", obj);
448 //dvmDumpThread(dvmThreadSelf(), false);
450 if (false && dvmIsClassObject((Object*)obj)) {
451 ClassObject* clazz = (ClassObject*) obj;
453 ALOGI("Adding global ref on class %s", clazz->descriptor);
454 dvmDumpThread(dvmThreadSelf(), false);
456 if (false && ((Object*)obj)->clazz == gDvm.classJavaLangString) {
457 StringObject* strObj = (StringObject*) obj;
458 char* str = dvmCreateCstrFromString(strObj);
459 if (strcmp(str, "sync-response") == 0) {
461 ALOGI("Adding global ref on string '%s'", str);
462 dvmDumpThread(dvmThreadSelf(), false);
467 if (false && ((Object*)obj)->clazz == gDvm.classArrayByte) {
468 ArrayObject* arrayObj = (ArrayObject*) obj;
469 if (arrayObj->length == 8192 /*&&
470 dvmReferenceTableEntries(&gDvm.jniGlobalRefTable) > 400*/)
472 ALOGI("Adding global ref on byte array %p (len=%d)",
473 arrayObj, arrayObj->length);
474 dvmDumpThread(dvmThreadSelf(), false);
478 ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
481 * Throwing an exception on failure is problematic, because JNI code
482 * may not be expecting an exception, and things sort of cascade. We
483 * want to have a hard limit to catch leaks during debugging, but this
484 * otherwise needs to expand until memory is consumed. As a practical
485 * matter, if we have many thousands of global references, chances are
486 * we're either leaking global ref table entries or we're going to
487 * run out of space in the GC heap.
489 jobject jobj = (jobject) gDvm.jniGlobalRefTable.add(IRT_FIRST_SEGMENT, obj);
491 gDvm.jniGlobalRefTable.dump("JNI global");
492 ALOGE("Failed adding to JNI global ref table (%zd entries)",
493 gDvm.jniGlobalRefTable.capacity());
497 LOGVV("GREF add %p (%s.%s)", obj,
498 dvmGetCurrentJNIMethod()->clazz->descriptor,
499 dvmGetCurrentJNIMethod()->name);
501 /* GREF usage tracking; should probably be disabled for production env */
502 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
503 int count = gDvm.jniGlobalRefTable.capacity();
504 // TODO: adjust for "holes"
505 if (count > gDvm.jniGlobalRefHiMark) {
506 ALOGD("GREF has increased to %d", count);
507 gDvm.jniGlobalRefHiMark += kGrefWaterInterval;
508 gDvm.jniGlobalRefLoMark += kGrefWaterInterval;
510 /* watch for "excessive" use; not generally appropriate */
511 if (count >= gDvm.jniGrefLimit) {
512 if (gDvmJni.warnOnly) {
513 ALOGW("Excessive JNI global references (%d)", count);
515 gDvm.jniGlobalRefTable.dump("JNI global");
516 ALOGE("Excessive JNI global references (%d)", count);
525 static jobject addWeakGlobalReference(Object* obj) {
530 ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
531 IndirectRefTable *table = &gDvm.jniWeakGlobalRefTable;
532 jobject jobj = (jobject) table->add(IRT_FIRST_SEGMENT, obj);
534 gDvm.jniWeakGlobalRefTable.dump("JNI weak global");
535 ALOGE("Failed adding to JNI weak global ref table (%zd entries)", table->capacity());
541 static void deleteWeakGlobalReference(jobject jobj) {
546 ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
547 IndirectRefTable *table = &gDvm.jniWeakGlobalRefTable;
548 if (!table->remove(IRT_FIRST_SEGMENT, jobj)) {
549 ALOGW("JNI: DeleteWeakGlobalRef(%p) failed to find entry", jobj);
554 * Remove a global reference. In most cases it's the entry most recently
555 * added, which makes this pretty quick.
557 * Thought: if it's not the most recent entry, just null it out. When we
558 * fill up, do a compaction pass before we expand the list.
560 static void deleteGlobalReference(jobject jobj) {
565 ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
566 if (!gDvm.jniGlobalRefTable.remove(IRT_FIRST_SEGMENT, jobj)) {
567 ALOGW("JNI: DeleteGlobalRef(%p) failed to find entry", jobj);
571 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
572 int count = gDvm.jniGlobalRefTable.capacity();
573 // TODO: not quite right, need to subtract holes
574 if (count < gDvm.jniGlobalRefLoMark) {
575 ALOGD("GREF has decreased to %d", count);
576 gDvm.jniGlobalRefHiMark -= kGrefWaterInterval;
577 gDvm.jniGlobalRefLoMark -= kGrefWaterInterval;
583 * Objects don't currently move, so we just need to create a reference
584 * that will ensure the array object isn't collected.
586 * We use a separate reference table, which is part of the GC root set.
588 static void pinPrimitiveArray(ArrayObject* arrayObj) {
589 if (arrayObj == NULL) {
593 ScopedPthreadMutexLock lock(&gDvm.jniPinRefLock);
595 if (!dvmAddToReferenceTable(&gDvm.jniPinRefTable, (Object*)arrayObj)) {
596 dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
597 ALOGE("Failed adding to JNI pinned array ref table (%d entries)",
598 (int) dvmReferenceTableEntries(&gDvm.jniPinRefTable));
603 * If we're watching global ref usage, also keep an eye on these.
605 * The total number of pinned primitive arrays should be pretty small.
606 * A single array should not be pinned more than once or twice; any
607 * more than that is a strong indicator that a Release function is
610 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
612 Object** ppObj = gDvm.jniPinRefTable.table;
613 while (ppObj < gDvm.jniPinRefTable.nextEntry) {
614 if (*ppObj++ == (Object*) arrayObj)
618 if (count > kPinComplainThreshold) {
619 ALOGW("JNI: pin count on array %p (%s) is now %d",
620 arrayObj, arrayObj->clazz->descriptor, count);
627 * Un-pin the array object. If an object was pinned twice, it must be
628 * unpinned twice before it's free to move.
630 static void unpinPrimitiveArray(ArrayObject* arrayObj) {
631 if (arrayObj == NULL) {
635 ScopedPthreadMutexLock lock(&gDvm.jniPinRefLock);
636 if (!dvmRemoveFromReferenceTable(&gDvm.jniPinRefTable,
637 gDvm.jniPinRefTable.table, (Object*) arrayObj))
639 ALOGW("JNI: unpinPrimitiveArray(%p) failed to find entry (valid=%d)",
640 arrayObj, dvmIsHeapAddress((Object*) arrayObj));
646 * Dump the contents of the JNI reference tables to the log file.
648 * We only dump the local refs associated with the current thread.
650 void dvmDumpJniReferenceTables() {
651 Thread* self = dvmThreadSelf();
652 self->jniLocalRefTable.dump("JNI local");
653 gDvm.jniGlobalRefTable.dump("JNI global");
654 dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
658 * Verify that a reference passed in from native code is one that the
659 * code is allowed to have.
661 * It's okay for native code to pass us a reference that:
662 * - was passed in as an argument when invoked by native code (and hence
663 * is in the JNI local refs table)
664 * - was returned to it from JNI (and is now in the local refs table)
665 * - is present in the JNI global refs table
667 * Used by -Xcheck:jni and GetObjectRefType.
669 jobjectRefType dvmGetJNIRefType(Thread* self, jobject jobj) {
671 * IndirectRefKind is currently defined as an exact match of
672 * jobjectRefType, so this is easy. We have to decode it to determine
673 * if it's a valid reference and not merely valid-looking.
675 assert(jobj != NULL);
677 Object* obj = dvmDecodeIndirectRef(self, jobj);
678 if (obj == reinterpret_cast<Object*>(jobj) && gDvmJni.workAroundAppJniBugs) {
679 // If we're handing out direct pointers, check whether 'jobj' is a direct reference
680 // to a local reference.
681 return self->jniLocalRefTable.contains(obj) ? JNILocalRefType : JNIInvalidRefType;
682 } else if (obj == kInvalidIndirectRefObject) {
683 return JNIInvalidRefType;
685 return (jobjectRefType) indirectRefKind(jobj);
689 static void dumpMethods(Method* methods, size_t methodCount, const char* name) {
691 for (i = 0; i < methodCount; ++i) {
692 Method* method = &methods[i];
693 if (strcmp(name, method->name) == 0) {
694 char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
695 ALOGE("Candidate: %s.%s:%s", method->clazz->descriptor, name, desc);
701 static void dumpCandidateMethods(ClassObject* clazz, const char* methodName, const char* signature) {
702 ALOGE("ERROR: couldn't find native method");
703 ALOGE("Requested: %s.%s:%s", clazz->descriptor, methodName, signature);
704 dumpMethods(clazz->virtualMethods, clazz->virtualMethodCount, methodName);
705 dumpMethods(clazz->directMethods, clazz->directMethodCount, methodName);
709 * Register a method that uses JNI calling conventions.
711 static bool dvmRegisterJNIMethod(ClassObject* clazz, const char* methodName,
712 const char* signature, void* fnPtr)
718 // If a signature starts with a '!', we take that as a sign that the native code doesn't
719 // need the extra JNI arguments (the JNIEnv* and the jclass).
720 bool fastJni = false;
721 if (*signature == '!') {
724 ALOGV("fast JNI method %s.%s:%s detected", clazz->descriptor, methodName, signature);
727 Method* method = dvmFindDirectMethodByDescriptor(clazz, methodName, signature);
728 if (method == NULL) {
729 method = dvmFindVirtualMethodByDescriptor(clazz, methodName, signature);
731 if (method == NULL) {
732 dumpCandidateMethods(clazz, methodName, signature);
736 if (!dvmIsNativeMethod(method)) {
737 ALOGW("Unable to register: not native: %s.%s:%s", clazz->descriptor, methodName, signature);
742 // In this case, we have extra constraints to check...
743 if (dvmIsSynchronizedMethod(method)) {
744 // Synchronization is usually provided by the JNI bridge,
745 // but we won't have one.
746 ALOGE("fast JNI method %s.%s:%s cannot be synchronized",
747 clazz->descriptor, methodName, signature);
750 if (!dvmIsStaticMethod(method)) {
751 // There's no real reason for this constraint, but since we won't
752 // be supplying a JNIEnv* or a jobject 'this', you're effectively
753 // static anyway, so it seems clearer to say so.
754 ALOGE("fast JNI method %s.%s:%s cannot be non-static",
755 clazz->descriptor, methodName, signature);
760 if (method->nativeFunc != dvmResolveNativeMethod) {
761 /* this is allowed, but unusual */
762 ALOGV("Note: %s.%s:%s was already registered", clazz->descriptor, methodName, signature);
765 method->fastJni = fastJni;
766 dvmUseJNIBridge(method, fnPtr);
768 ALOGV("JNI-registered %s.%s:%s", clazz->descriptor, methodName, signature);
772 static const char* builtInPrefixes[] = {
775 "Lcom/google/android/",
780 "Lorg/apache/harmony/",
783 static bool shouldTrace(Method* method) {
784 const char* className = method->clazz->descriptor;
785 // Return true if the -Xjnitrace setting implies we should trace 'method'.
786 if (gDvm.jniTrace && strstr(className, gDvm.jniTrace)) {
789 // Return true if we're trying to log all third-party JNI activity and 'method' doesn't look
790 // like part of Android.
791 if (gDvmJni.logThirdPartyJni) {
792 for (size_t i = 0; i < NELEM(builtInPrefixes); ++i) {
793 if (strstr(className, builtInPrefixes[i]) == className) {
803 * Point "method->nativeFunc" at the JNI bridge, and overload "method->insns"
804 * to point at the actual function.
806 void dvmUseJNIBridge(Method* method, void* func) {
807 method->shouldTrace = shouldTrace(method);
809 // Does the method take any reference arguments?
810 method->noRef = true;
811 const char* cp = method->shorty;
812 while (*++cp != '\0') { // Pre-increment to skip return type.
814 method->noRef = false;
819 DalvikBridgeFunc bridge = gDvmJni.useCheckJni ? dvmCheckCallJNIMethod : dvmCallJNIMethod;
820 dvmSetNativeFunc(method, bridge, (const u2*) func);
823 // TODO: rewrite this to share code with CheckJNI's tracing...
824 static void appendValue(char type, const JValue value, char* buf, size_t n, bool appendComma)
826 size_t len = strlen(buf);
827 if (len >= n - 32) { // 32 should be longer than anything we could append.
836 if (value.b >= 0 && value.b < 10) {
837 sprintf(p, "%d", value.b);
839 sprintf(p, "%#x (%d)", value.b, value.b);
843 if (value.c < 0x7f && value.c >= ' ') {
844 sprintf(p, "U+%x ('%c')", value.c, value.c);
846 sprintf(p, "U+%x", value.c);
850 sprintf(p, "%g", value.d);
853 sprintf(p, "%g", value.f);
856 sprintf(p, "%d", value.i);
859 sprintf(p, "%#x", value.i);
862 sprintf(p, "%lld", value.j);
865 sprintf(p, "%d", value.s);
871 strcpy(p, value.z ? "true" : "false");
874 sprintf(p, "unknown type '%c'", type);
883 static void logNativeMethodEntry(const Method* method, const u4* args)
885 char thisString[32] = { 0 };
887 if (!dvmIsStaticMethod(method)) {
888 sprintf(thisString, "this=0x%08x ", *sp++);
891 char argsString[128]= { 0 };
892 const char* desc = &method->shorty[1];
893 while (*desc != '\0') {
894 char argType = *desc++;
896 if (argType == 'D' || argType == 'J') {
897 value.j = dvmGetArgLong(sp, 0);
902 appendValue(argType, value, argsString, sizeof(argsString),
906 std::string className(dvmHumanReadableDescriptor(method->clazz->descriptor));
907 char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
908 ALOGI("-> %s %s%s %s(%s)", className.c_str(), method->name, signature, thisString, argsString);
912 static void logNativeMethodExit(const Method* method, Thread* self, const JValue returnValue)
914 std::string className(dvmHumanReadableDescriptor(method->clazz->descriptor));
915 char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
916 if (dvmCheckException(self)) {
917 Object* exception = dvmGetException(self);
918 std::string exceptionClassName(dvmHumanReadableDescriptor(exception->clazz->descriptor));
919 ALOGI("<- %s %s%s threw %s", className.c_str(),
920 method->name, signature, exceptionClassName.c_str());
922 char returnValueString[128] = { 0 };
923 char returnType = method->shorty[0];
924 appendValue(returnType, returnValue, returnValueString, sizeof(returnValueString), false);
925 ALOGI("<- %s %s%s returned %s", className.c_str(),
926 method->name, signature, returnValueString);
932 * Get the method currently being executed by examining the interp stack.
934 const Method* dvmGetCurrentJNIMethod() {
935 assert(dvmThreadSelf() != NULL);
937 void* fp = dvmThreadSelf()->interpSave.curFrame;
938 const Method* meth = SAVEAREA_FROM_FP(fp)->method;
940 assert(meth != NULL);
941 assert(dvmIsNativeMethod(meth));
946 * Track a JNI MonitorEnter in the current thread.
948 * The goal is to be able to "implicitly" release all JNI-held monitors
949 * when the thread detaches.
951 * Monitors may be entered multiple times, so we add a new entry for each
952 * enter call. It would be more efficient to keep a counter. At present
953 * there's no real motivation to improve this however.
955 static void trackMonitorEnter(Thread* self, Object* obj) {
956 static const int kInitialSize = 16;
957 ReferenceTable* refTable = &self->jniMonitorRefTable;
959 /* init table on first use */
960 if (refTable->table == NULL) {
961 assert(refTable->maxEntries == 0);
963 if (!dvmInitReferenceTable(refTable, kInitialSize, INT_MAX)) {
964 ALOGE("Unable to initialize monitor tracking table");
969 if (!dvmAddToReferenceTable(refTable, obj)) {
970 /* ran out of memory? could throw exception instead */
971 ALOGE("Unable to add entry to monitor tracking table");
974 LOGVV("--- added monitor %p", obj);
979 * Track a JNI MonitorExit in the current thread.
981 static void trackMonitorExit(Thread* self, Object* obj) {
982 ReferenceTable* pRefTable = &self->jniMonitorRefTable;
984 if (!dvmRemoveFromReferenceTable(pRefTable, pRefTable->table, obj)) {
985 ALOGE("JNI monitor %p not found in tracking list", obj);
988 LOGVV("--- removed monitor %p", obj);
993 * Release all monitors held by the jniMonitorRefTable list.
995 void dvmReleaseJniMonitors(Thread* self) {
996 ReferenceTable* pRefTable = &self->jniMonitorRefTable;
997 Object** top = pRefTable->table;
1002 Object** ptr = pRefTable->nextEntry;
1003 while (--ptr >= top) {
1004 if (!dvmUnlockObject(self, *ptr)) {
1005 ALOGW("Unable to unlock monitor %p at thread detach", *ptr);
1007 LOGVV("--- detach-releasing monitor %p", *ptr);
1012 pRefTable->nextEntry = pRefTable->table;
1016 * Determine if the specified class can be instantiated from JNI. This
1017 * is used by AllocObject / NewObject, which are documented as throwing
1018 * an exception for abstract and interface classes, and not accepting
1019 * array classes. We also want to reject attempts to create new Class
1020 * objects, since only DefineClass should do that.
1022 static bool canAllocClass(ClassObject* clazz) {
1023 if (dvmIsAbstractClass(clazz) || dvmIsInterfaceClass(clazz)) {
1024 /* JNI spec defines what this throws */
1025 dvmThrowInstantiationException(clazz, "abstract class or interface");
1027 } else if (dvmIsArrayClass(clazz) || dvmIsTheClassClass(clazz)) {
1028 /* spec says "must not" for arrays, ignores Class */
1029 dvmThrowInstantiationException(clazz, "wrong JNI function");
1037 * ===========================================================================
1039 * ===========================================================================
1043 * The functions here form a bridge between interpreted code and JNI native
1044 * functions. The basic task is to convert an array of primitives and
1045 * references into C-style function arguments. This is architecture-specific
1046 * and usually requires help from assembly code.
1048 * The bridge takes four arguments: the array of parameters, a place to
1049 * store the function result (if any), the method to call, and a pointer
1050 * to the current thread.
1052 * These functions aren't called directly from elsewhere in the VM.
1053 * A pointer in the Method struct points to one of these, and when a native
1054 * method is invoked the interpreter jumps to it.
1056 * (The "internal native" methods are invoked the same way, but instead
1057 * of calling through a bridge, the target method is called directly.)
1059 * The "args" array should not be modified, but we do so anyway for
1060 * performance reasons. We know that it points to the "outs" area on
1061 * the current method's interpreted stack. This area is ignored by the
1062 * precise GC, because there is no register map for a native method (for
1063 * an interpreted method the args would be listed in the argument set).
1064 * We know all of the values exist elsewhere on the interpreted stack,
1065 * because the method call setup copies them right before making the call,
1066 * so we don't have to worry about concealing stuff from the GC.
1068 * If we don't want to modify "args", we either have to create a local
1069 * copy and modify it before calling dvmPlatformInvoke, or we have to do
1070 * the local reference replacement within dvmPlatformInvoke. The latter
1071 * has some performance advantages, though if we can inline the local
1072 * reference adds we may win when there's a lot of reference args (unless
1073 * we want to code up some local ref table manipulation in assembly.
1077 * If necessary, convert the value in pResult from a local/global reference
1078 * to an object pointer.
1080 * If the returned reference is invalid, kInvalidIndirectRefObject will
1081 * be returned in pResult.
1083 static inline void convertReferenceResult(JNIEnv* env, JValue* pResult,
1084 const Method* method, Thread* self)
1086 if (method->shorty[0] == 'L' && !dvmCheckException(self) && pResult->l != NULL) {
1087 pResult->l = dvmDecodeIndirectRef(self, (jobject) pResult->l);
1092 * General form, handles all cases.
1094 void dvmCallJNIMethod(const u4* args, JValue* pResult, const Method* method, Thread* self) {
1095 u4* modArgs = (u4*) args;
1096 jclass staticMethodClass = NULL;
1098 u4 accessFlags = method->accessFlags;
1099 bool isSynchronized = (accessFlags & ACC_SYNCHRONIZED) != 0;
1101 //ALOGI("JNI calling %p (%s.%s:%s):", method->insns,
1102 // method->clazz->descriptor, method->name, method->shorty);
1105 * Walk the argument list, creating local references for appropriate
1110 if ((accessFlags & ACC_STATIC) != 0) {
1111 lockObj = (Object*) method->clazz;
1112 /* add the class object we pass in */
1113 staticMethodClass = (jclass) addLocalReference(self, (Object*) method->clazz);
1115 lockObj = (Object*) args[0];
1117 modArgs[idx++] = (u4) addLocalReference(self, (Object*) modArgs[0]);
1120 if (!method->noRef) {
1121 const char* shorty = &method->shorty[1]; /* skip return type */
1122 while (*shorty != '\0') {
1123 switch (*shorty++) {
1125 //ALOGI(" local %d: 0x%08x", idx, modArgs[idx]);
1126 if (modArgs[idx] != 0) {
1127 modArgs[idx] = (u4) addLocalReference(self, (Object*) modArgs[idx]);
1135 /* Z B C S I -- do nothing */
1142 if (UNLIKELY(method->shouldTrace)) {
1143 logNativeMethodEntry(method, args);
1145 if (UNLIKELY(isSynchronized)) {
1146 dvmLockObject(self, lockObj);
1149 ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
1151 ANDROID_MEMBAR_FULL(); /* guarantee ordering on method->insns */
1152 assert(method->insns != NULL);
1154 JNIEnv* env = self->jniEnv;
1155 COMPUTE_STACK_SUM(self);
1156 dvmPlatformInvoke(env,
1157 (ClassObject*) staticMethodClass,
1158 method->jniArgInfo, method->insSize, modArgs, method->shorty,
1159 (void*) method->insns, pResult);
1160 CHECK_STACK_SUM(self);
1162 dvmChangeStatus(self, oldStatus);
1164 convertReferenceResult(env, pResult, method, self);
1166 if (UNLIKELY(isSynchronized)) {
1167 dvmUnlockObject(self, lockObj);
1169 if (UNLIKELY(method->shouldTrace)) {
1170 logNativeMethodExit(method, self, *pResult);
1175 * ===========================================================================
1176 * JNI implementation
1177 * ===========================================================================
1181 * Return the version of the native method interface.
1183 static jint GetVersion(JNIEnv* env) {
1185 * There is absolutely no need to toggle the mode for correct behavior.
1186 * However, it does provide native code with a simple "suspend self
1187 * if necessary" call.
1189 ScopedJniThreadState ts(env);
1190 return JNI_VERSION_1_6;
1194 * Create a new class from a bag of bytes.
1196 * This is not currently supported within Dalvik.
1198 static jclass DefineClass(JNIEnv* env, const char *name, jobject loader,
1199 const jbyte* buf, jsize bufLen)
1201 UNUSED_PARAMETER(name);
1202 UNUSED_PARAMETER(loader);
1203 UNUSED_PARAMETER(buf);
1204 UNUSED_PARAMETER(bufLen);
1206 ScopedJniThreadState ts(env);
1207 ALOGW("JNI DefineClass is not supported");
1212 * Find a class by name.
1214 * We have to use the "no init" version of FindClass here, because we might
1215 * be getting the class prior to registering native methods that will be
1218 * We need to get the class loader associated with the current native
1219 * method. If there is no native method, e.g. we're calling this from native
1220 * code right after creating the VM, the spec says we need to use the class
1221 * loader returned by "ClassLoader.getBaseClassLoader". There is no such
1222 * method, but it's likely they meant ClassLoader.getSystemClassLoader.
1223 * We can't get that until after the VM has initialized though.
1225 static jclass FindClass(JNIEnv* env, const char* name) {
1226 ScopedJniThreadState ts(env);
1228 const Method* thisMethod = dvmGetCurrentJNIMethod();
1229 assert(thisMethod != NULL);
1232 Object* trackedLoader = NULL;
1233 if (ts.self()->classLoaderOverride != NULL) {
1234 /* hack for JNI_OnLoad */
1235 assert(strcmp(thisMethod->name, "nativeLoad") == 0);
1236 loader = ts.self()->classLoaderOverride;
1237 } else if (thisMethod == gDvm.methDalvikSystemNativeStart_main ||
1238 thisMethod == gDvm.methDalvikSystemNativeStart_run) {
1239 /* start point of invocation interface */
1240 if (!gDvm.initializing) {
1241 loader = trackedLoader = dvmGetSystemClassLoader();
1246 loader = thisMethod->clazz->classLoader;
1249 char* descriptor = dvmNameToDescriptor(name);
1250 if (descriptor == NULL) {
1253 ClassObject* clazz = dvmFindClassNoInit(descriptor, loader);
1256 jclass jclazz = (jclass) addLocalReference(ts.self(), (Object*) clazz);
1257 dvmReleaseTrackedAlloc(trackedLoader, ts.self());
1262 * Return the superclass of a class.
1264 static jclass GetSuperclass(JNIEnv* env, jclass jclazz) {
1265 ScopedJniThreadState ts(env);
1266 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1267 return (jclass) addLocalReference(ts.self(), (Object*)clazz->super);
1271 * Determine whether an object of clazz1 can be safely cast to clazz2.
1273 * Like IsInstanceOf, but with a pair of class objects instead of obj+class.
1275 static jboolean IsAssignableFrom(JNIEnv* env, jclass jclazz1, jclass jclazz2) {
1276 ScopedJniThreadState ts(env);
1277 ClassObject* clazz1 = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz1);
1278 ClassObject* clazz2 = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz2);
1279 return dvmInstanceof(clazz1, clazz2);
1283 * Given a java.lang.reflect.Method or .Constructor, return a methodID.
1285 static jmethodID FromReflectedMethod(JNIEnv* env, jobject jmethod) {
1286 ScopedJniThreadState ts(env);
1287 Object* method = dvmDecodeIndirectRef(ts.self(), jmethod);
1288 return (jmethodID) dvmGetMethodFromReflectObj(method);
1292 * Given a java.lang.reflect.Field, return a fieldID.
1294 static jfieldID FromReflectedField(JNIEnv* env, jobject jfield) {
1295 ScopedJniThreadState ts(env);
1296 Object* field = dvmDecodeIndirectRef(ts.self(), jfield);
1297 return (jfieldID) dvmGetFieldFromReflectObj(field);
1301 * Convert a methodID to a java.lang.reflect.Method or .Constructor.
1303 * (The "isStatic" field does not appear in the spec.)
1305 * Throws OutOfMemory and returns NULL on failure.
1307 static jobject ToReflectedMethod(JNIEnv* env, jclass jcls, jmethodID methodID, jboolean isStatic) {
1308 ScopedJniThreadState ts(env);
1309 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jcls);
1310 Object* obj = dvmCreateReflectObjForMethod(clazz, (Method*) methodID);
1311 dvmReleaseTrackedAlloc(obj, NULL);
1312 return addLocalReference(ts.self(), obj);
1316 * Convert a fieldID to a java.lang.reflect.Field.
1318 * (The "isStatic" field does not appear in the spec.)
1320 * Throws OutOfMemory and returns NULL on failure.
1322 static jobject ToReflectedField(JNIEnv* env, jclass jcls, jfieldID fieldID, jboolean isStatic) {
1323 ScopedJniThreadState ts(env);
1324 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jcls);
1325 Object* obj = dvmCreateReflectObjForField(clazz, (Field*) fieldID);
1326 dvmReleaseTrackedAlloc(obj, NULL);
1327 return addLocalReference(ts.self(), obj);
1331 * Take this exception and throw it.
1333 static jint Throw(JNIEnv* env, jthrowable jobj) {
1334 ScopedJniThreadState ts(env);
1336 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1337 dvmSetException(ts.self(), obj);
1344 * Constructs an exception object from the specified class with the message
1345 * specified by "message", and throws it.
1347 static jint ThrowNew(JNIEnv* env, jclass jclazz, const char* message) {
1348 ScopedJniThreadState ts(env);
1349 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1350 dvmThrowException(clazz, message);
1351 // TODO: should return failure if this didn't work (e.g. OOM)
1356 * If an exception is being thrown, return the exception object. Otherwise,
1359 * TODO: if there is no pending exception, we should be able to skip the
1360 * enter/exit checks. If we find one, we need to enter and then re-fetch
1361 * the exception (in case it got moved by a compacting GC).
1363 static jthrowable ExceptionOccurred(JNIEnv* env) {
1364 ScopedJniThreadState ts(env);
1365 Object* exception = dvmGetException(ts.self());
1366 jthrowable localException = (jthrowable) addLocalReference(ts.self(), exception);
1367 if (localException == NULL && exception != NULL) {
1369 * We were unable to add a new local reference, and threw a new
1370 * exception. We can't return "exception", because it's not a
1371 * local reference. So we have to return NULL, indicating that
1372 * there was no exception, even though it's pretty much raining
1373 * exceptions in here.
1375 ALOGW("JNI WARNING: addLocal/exception combo");
1377 return localException;
1381 * Print an exception and stack trace to stderr.
1383 static void ExceptionDescribe(JNIEnv* env) {
1384 ScopedJniThreadState ts(env);
1385 Object* exception = dvmGetException(ts.self());
1386 if (exception != NULL) {
1387 dvmPrintExceptionStackTrace();
1389 ALOGI("Odd: ExceptionDescribe called, but no exception pending");
1394 * Clear the exception currently being thrown.
1396 * TODO: we should be able to skip the enter/exit stuff.
1398 static void ExceptionClear(JNIEnv* env) {
1399 ScopedJniThreadState ts(env);
1400 dvmClearException(ts.self());
1404 * Kill the VM. This function does not return.
1406 static void FatalError(JNIEnv* env, const char* msg) {
1407 //dvmChangeStatus(NULL, THREAD_RUNNING);
1408 ALOGE("JNI posting fatal error: %s", msg);
1413 * Push a new JNI frame on the stack, with a new set of locals.
1415 * The new frame must have the same method pointer. (If for no other
1416 * reason than FindClass needs it to get the appropriate class loader.)
1418 static jint PushLocalFrame(JNIEnv* env, jint capacity) {
1419 ScopedJniThreadState ts(env);
1420 if (!ensureLocalCapacity(ts.self(), capacity) ||
1421 !dvmPushLocalFrame(ts.self(), dvmGetCurrentJNIMethod()))
1423 /* yes, OutOfMemoryError, not StackOverflowError */
1424 dvmClearException(ts.self());
1425 dvmThrowOutOfMemoryError("out of stack in JNI PushLocalFrame");
1432 * Pop the local frame off. If "jresult" is not null, add it as a
1433 * local reference on the now-current frame.
1435 static jobject PopLocalFrame(JNIEnv* env, jobject jresult) {
1436 ScopedJniThreadState ts(env);
1437 Object* result = dvmDecodeIndirectRef(ts.self(), jresult);
1438 if (!dvmPopLocalFrame(ts.self())) {
1439 ALOGW("JNI WARNING: too many PopLocalFrame calls");
1440 dvmClearException(ts.self());
1441 dvmThrowRuntimeException("too many PopLocalFrame calls");
1443 return addLocalReference(ts.self(), result);
1447 * Add a reference to the global list.
1449 static jobject NewGlobalRef(JNIEnv* env, jobject jobj) {
1450 ScopedJniThreadState ts(env);
1451 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1452 return addGlobalReference(obj);
1456 * Delete a reference from the global list.
1458 static void DeleteGlobalRef(JNIEnv* env, jobject jglobalRef) {
1459 ScopedJniThreadState ts(env);
1460 deleteGlobalReference(jglobalRef);
1465 * Add a reference to the local list.
1467 static jobject NewLocalRef(JNIEnv* env, jobject jobj) {
1468 ScopedJniThreadState ts(env);
1469 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1470 return addLocalReference(ts.self(), obj);
1474 * Delete a reference from the local list.
1476 static void DeleteLocalRef(JNIEnv* env, jobject jlocalRef) {
1477 ScopedJniThreadState ts(env);
1478 deleteLocalReference(ts.self(), jlocalRef);
1482 * Ensure that the local references table can hold at least this many
1485 static jint EnsureLocalCapacity(JNIEnv* env, jint capacity) {
1486 ScopedJniThreadState ts(env);
1487 bool okay = ensureLocalCapacity(ts.self(), capacity);
1489 dvmThrowOutOfMemoryError("can't ensure local reference capacity");
1491 return okay ? 0 : -1;
1496 * Determine whether two Object references refer to the same underlying object.
1498 static jboolean IsSameObject(JNIEnv* env, jobject jref1, jobject jref2) {
1499 ScopedJniThreadState ts(env);
1500 Object* obj1 = dvmDecodeIndirectRef(ts.self(), jref1);
1501 Object* obj2 = dvmDecodeIndirectRef(ts.self(), jref2);
1502 return (obj1 == obj2);
1506 * Allocate a new object without invoking any constructors.
1508 static jobject AllocObject(JNIEnv* env, jclass jclazz) {
1509 ScopedJniThreadState ts(env);
1511 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1512 if (!canAllocClass(clazz) ||
1513 (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)))
1515 assert(dvmCheckException(ts.self()));
1519 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1520 return addLocalReference(ts.self(), newObj);
1524 * Allocate a new object and invoke the supplied constructor.
1526 static jobject NewObject(JNIEnv* env, jclass jclazz, jmethodID methodID, ...) {
1527 ScopedJniThreadState ts(env);
1528 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1530 if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
1531 assert(dvmCheckException(ts.self()));
1535 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1536 jobject result = addLocalReference(ts.self(), newObj);
1537 if (newObj != NULL) {
1540 va_start(args, methodID);
1541 dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args);
1547 static jobject NewObjectV(JNIEnv* env, jclass jclazz, jmethodID methodID, va_list args) {
1548 ScopedJniThreadState ts(env);
1549 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1551 if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
1552 assert(dvmCheckException(ts.self()));
1556 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1557 jobject result = addLocalReference(ts.self(), newObj);
1558 if (newObj != NULL) {
1560 dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args);
1565 static jobject NewObjectA(JNIEnv* env, jclass jclazz, jmethodID methodID, jvalue* args) {
1566 ScopedJniThreadState ts(env);
1567 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1569 if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
1570 assert(dvmCheckException(ts.self()));
1574 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1575 jobject result = addLocalReference(ts.self(), newObj);
1576 if (newObj != NULL) {
1578 dvmCallMethodA(ts.self(), (Method*) methodID, newObj, true, &unused, args);
1584 * Returns the class of an object.
1586 * JNI spec says: obj must not be NULL.
1588 static jclass GetObjectClass(JNIEnv* env, jobject jobj) {
1589 ScopedJniThreadState ts(env);
1591 assert(jobj != NULL);
1593 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1594 return (jclass) addLocalReference(ts.self(), (Object*) obj->clazz);
1598 * Determine whether "obj" is an instance of "clazz".
1600 static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass jclazz) {
1601 ScopedJniThreadState ts(env);
1603 assert(jclazz != NULL);
1608 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1609 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1610 return dvmInstanceof(obj->clazz, clazz);
1614 * Get a method ID for an instance method.
1616 * While Dalvik bytecode has distinct instructions for virtual, super,
1617 * static, direct, and interface method invocation, JNI only provides
1618 * two functions for acquiring a method ID. This call handles everything
1619 * but static methods.
1621 * JNI defines <init> as an instance method, but Dalvik considers it a
1622 * "direct" method, so we have to special-case it here.
1624 * Dalvik also puts all private methods into the "direct" list, so we
1625 * really need to just search both lists.
1627 static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1628 ScopedJniThreadState ts(env);
1630 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1631 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1632 assert(dvmCheckException(ts.self()));
1633 } else if (dvmIsInterfaceClass(clazz)) {
1634 Method* meth = dvmFindInterfaceMethodHierByDescriptor(clazz, name, sig);
1636 dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
1637 "no method with name='%s' signature='%s' in interface %s",
1638 name, sig, clazz->descriptor);
1640 return (jmethodID) meth;
1642 Method* meth = dvmFindVirtualMethodHierByDescriptor(clazz, name, sig);
1644 /* search private methods and constructors; non-hierarchical */
1645 meth = dvmFindDirectMethodByDescriptor(clazz, name, sig);
1647 if (meth != NULL && dvmIsStaticMethod(meth)) {
1649 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
1650 ALOGD("GetMethodID: not returning static method %s.%s %s",
1651 clazz->descriptor, meth->name, desc);
1657 dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
1658 "no method with name='%s' signature='%s' in class %s",
1659 name, sig, clazz->descriptor);
1662 * The method's class may not be the same as clazz, but if
1663 * it isn't this must be a virtual method and the class must
1664 * be a superclass (and, hence, already initialized).
1666 assert(dvmIsClassInitialized(meth->clazz) || dvmIsClassInitializing(meth->clazz));
1668 return (jmethodID) meth;
1672 * Get a field ID (instance fields).
1674 static jfieldID GetFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1675 ScopedJniThreadState ts(env);
1677 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1679 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1680 assert(dvmCheckException(ts.self()));
1684 jfieldID id = (jfieldID) dvmFindInstanceFieldHier(clazz, name, sig);
1686 dvmThrowExceptionFmt(gDvm.exNoSuchFieldError,
1687 "no field with name='%s' signature='%s' in class %s",
1688 name, sig, clazz->descriptor);
1694 * Get the method ID for a static method in a class.
1696 static jmethodID GetStaticMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1697 ScopedJniThreadState ts(env);
1699 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1700 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1701 assert(dvmCheckException(ts.self()));
1705 Method* meth = dvmFindDirectMethodHierByDescriptor(clazz, name, sig);
1707 /* make sure it's static, not virtual+private */
1708 if (meth != NULL && !dvmIsStaticMethod(meth)) {
1710 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
1711 ALOGD("GetStaticMethodID: not returning nonstatic method %s.%s %s",
1712 clazz->descriptor, meth->name, desc);
1718 jmethodID id = (jmethodID) meth;
1720 dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
1721 "no static method with name='%s' signature='%s' in class %s",
1722 name, sig, clazz->descriptor);
1728 * Get a field ID (static fields).
1730 static jfieldID GetStaticFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1731 ScopedJniThreadState ts(env);
1733 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1734 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1735 assert(dvmCheckException(ts.self()));
1739 jfieldID id = (jfieldID) dvmFindStaticFieldHier(clazz, name, sig);
1741 dvmThrowExceptionFmt(gDvm.exNoSuchFieldError,
1742 "no static field with name='%s' signature='%s' in class %s",
1743 name, sig, clazz->descriptor);
1749 * Get a static field.
1751 * If we get an object reference, add it to the local refs list.
1753 #define GET_STATIC_TYPE_FIELD(_ctype, _jname, _isref) \
1754 static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass jclazz, \
1757 UNUSED_PARAMETER(jclazz); \
1758 ScopedJniThreadState ts(env); \
1759 StaticField* sfield = (StaticField*) fieldID; \
1761 if (dvmIsVolatileField(sfield)) { \
1762 if (_isref) { /* only when _ctype==jobject */ \
1763 Object* obj = dvmGetStaticFieldObjectVolatile(sfield); \
1764 value = (_ctype)(u4)addLocalReference(ts.self(), obj); \
1766 value = (_ctype) dvmGetStaticField##_jname##Volatile(sfield);\
1770 Object* obj = dvmGetStaticFieldObject(sfield); \
1771 value = (_ctype)(u4)addLocalReference(ts.self(), obj); \
1773 value = (_ctype) dvmGetStaticField##_jname(sfield); \
1778 GET_STATIC_TYPE_FIELD(jobject, Object, true);
1779 GET_STATIC_TYPE_FIELD(jboolean, Boolean, false);
1780 GET_STATIC_TYPE_FIELD(jbyte, Byte, false);
1781 GET_STATIC_TYPE_FIELD(jchar, Char, false);
1782 GET_STATIC_TYPE_FIELD(jshort, Short, false);
1783 GET_STATIC_TYPE_FIELD(jint, Int, false);
1784 GET_STATIC_TYPE_FIELD(jlong, Long, false);
1785 GET_STATIC_TYPE_FIELD(jfloat, Float, false);
1786 GET_STATIC_TYPE_FIELD(jdouble, Double, false);
1789 * Set a static field.
1791 #define SET_STATIC_TYPE_FIELD(_ctype, _ctype2, _jname, _isref) \
1792 static void SetStatic##_jname##Field(JNIEnv* env, jclass jclazz, \
1793 jfieldID fieldID, _ctype value) \
1795 UNUSED_PARAMETER(jclazz); \
1796 ScopedJniThreadState ts(env); \
1797 StaticField* sfield = (StaticField*) fieldID; \
1798 if (dvmIsVolatileField(sfield)) { \
1799 if (_isref) { /* only when _ctype==jobject */ \
1800 Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1801 dvmSetStaticFieldObjectVolatile(sfield, valObj); \
1803 dvmSetStaticField##_jname##Volatile(sfield, (_ctype2)value);\
1807 Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1808 dvmSetStaticFieldObject(sfield, valObj); \
1810 dvmSetStaticField##_jname(sfield, (_ctype2)value); \
1814 SET_STATIC_TYPE_FIELD(jobject, Object*, Object, true);
1815 SET_STATIC_TYPE_FIELD(jboolean, bool, Boolean, false);
1816 SET_STATIC_TYPE_FIELD(jbyte, s1, Byte, false);
1817 SET_STATIC_TYPE_FIELD(jchar, u2, Char, false);
1818 SET_STATIC_TYPE_FIELD(jshort, s2, Short, false);
1819 SET_STATIC_TYPE_FIELD(jint, s4, Int, false);
1820 SET_STATIC_TYPE_FIELD(jlong, s8, Long, false);
1821 SET_STATIC_TYPE_FIELD(jfloat, float, Float, false);
1822 SET_STATIC_TYPE_FIELD(jdouble, double, Double, false);
1825 * Get an instance field.
1827 * If we get an object reference, add it to the local refs list.
1829 #define GET_TYPE_FIELD(_ctype, _jname, _isref) \
1830 static _ctype Get##_jname##Field(JNIEnv* env, jobject jobj, \
1833 ScopedJniThreadState ts(env); \
1834 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1835 InstField* field = (InstField*) fieldID; \
1837 if (dvmIsVolatileField(field)) { \
1838 if (_isref) { /* only when _ctype==jobject */ \
1840 dvmGetFieldObjectVolatile(obj, field->byteOffset); \
1841 value = (_ctype)(u4)addLocalReference(ts.self(), valObj); \
1844 dvmGetField##_jname##Volatile(obj, field->byteOffset); \
1848 Object* valObj = dvmGetFieldObject(obj, field->byteOffset); \
1849 value = (_ctype)(u4)addLocalReference(ts.self(), valObj); \
1851 value = (_ctype) dvmGetField##_jname(obj, field->byteOffset);\
1856 GET_TYPE_FIELD(jobject, Object, true);
1857 GET_TYPE_FIELD(jboolean, Boolean, false);
1858 GET_TYPE_FIELD(jbyte, Byte, false);
1859 GET_TYPE_FIELD(jchar, Char, false);
1860 GET_TYPE_FIELD(jshort, Short, false);
1861 GET_TYPE_FIELD(jint, Int, false);
1862 GET_TYPE_FIELD(jlong, Long, false);
1863 GET_TYPE_FIELD(jfloat, Float, false);
1864 GET_TYPE_FIELD(jdouble, Double, false);
1867 * Set an instance field.
1869 #define SET_TYPE_FIELD(_ctype, _ctype2, _jname, _isref) \
1870 static void Set##_jname##Field(JNIEnv* env, jobject jobj, \
1871 jfieldID fieldID, _ctype value) \
1873 ScopedJniThreadState ts(env); \
1874 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1875 InstField* field = (InstField*) fieldID; \
1876 if (dvmIsVolatileField(field)) { \
1877 if (_isref) { /* only when _ctype==jobject */ \
1878 Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1879 dvmSetFieldObjectVolatile(obj, field->byteOffset, valObj); \
1881 dvmSetField##_jname##Volatile(obj, \
1882 field->byteOffset, (_ctype2)value); \
1886 Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1887 dvmSetFieldObject(obj, field->byteOffset, valObj); \
1889 dvmSetField##_jname(obj, \
1890 field->byteOffset, (_ctype2)value); \
1894 SET_TYPE_FIELD(jobject, Object*, Object, true);
1895 SET_TYPE_FIELD(jboolean, bool, Boolean, false);
1896 SET_TYPE_FIELD(jbyte, s1, Byte, false);
1897 SET_TYPE_FIELD(jchar, u2, Char, false);
1898 SET_TYPE_FIELD(jshort, s2, Short, false);
1899 SET_TYPE_FIELD(jint, s4, Int, false);
1900 SET_TYPE_FIELD(jlong, s8, Long, false);
1901 SET_TYPE_FIELD(jfloat, float, Float, false);
1902 SET_TYPE_FIELD(jdouble, double, Double, false);
1905 * Make a virtual method call.
1907 * Three versions (..., va_list, jvalue[]) for each return type. If we're
1908 * returning an Object, we have to add it to the local references table.
1910 #define CALL_VIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \
1911 static _ctype Call##_jname##Method(JNIEnv* env, jobject jobj, \
1912 jmethodID methodID, ...) \
1914 ScopedJniThreadState ts(env); \
1915 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1916 const Method* meth; \
1919 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
1920 if (meth == NULL) { \
1923 va_start(args, methodID); \
1924 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \
1926 if (_isref && !dvmCheckException(ts.self())) \
1927 result.l = (Object*)addLocalReference(ts.self(), result.l); \
1930 static _ctype Call##_jname##MethodV(JNIEnv* env, jobject jobj, \
1931 jmethodID methodID, va_list args) \
1933 ScopedJniThreadState ts(env); \
1934 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1935 const Method* meth; \
1937 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
1938 if (meth == NULL) { \
1941 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \
1942 if (_isref && !dvmCheckException(ts.self())) \
1943 result.l = (Object*)addLocalReference(ts.self(), result.l); \
1946 static _ctype Call##_jname##MethodA(JNIEnv* env, jobject jobj, \
1947 jmethodID methodID, jvalue* args) \
1949 ScopedJniThreadState ts(env); \
1950 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1951 const Method* meth; \
1953 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
1954 if (meth == NULL) { \
1957 dvmCallMethodA(ts.self(), meth, obj, true, &result, args); \
1958 if (_isref && !dvmCheckException(ts.self())) \
1959 result.l = (Object*)addLocalReference(ts.self(), result.l); \
1962 CALL_VIRTUAL(jobject, Object, NULL, (jobject) result.l, true);
1963 CALL_VIRTUAL(jboolean, Boolean, 0, result.z, false);
1964 CALL_VIRTUAL(jbyte, Byte, 0, result.b, false);
1965 CALL_VIRTUAL(jchar, Char, 0, result.c, false);
1966 CALL_VIRTUAL(jshort, Short, 0, result.s, false);
1967 CALL_VIRTUAL(jint, Int, 0, result.i, false);
1968 CALL_VIRTUAL(jlong, Long, 0, result.j, false);
1969 CALL_VIRTUAL(jfloat, Float, 0.0f, result.f, false);
1970 CALL_VIRTUAL(jdouble, Double, 0.0, result.d, false);
1971 CALL_VIRTUAL(void, Void, , , false);
1974 * Make a "non-virtual" method call. We're still calling a virtual method,
1975 * but this time we're not doing an indirection through the object's vtable.
1976 * The "clazz" parameter defines which implementation of a method we want.
1978 * Three versions (..., va_list, jvalue[]) for each return type.
1980 #define CALL_NONVIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \
1981 static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, jobject jobj, \
1982 jclass jclazz, jmethodID methodID, ...) \
1984 ScopedJniThreadState ts(env); \
1985 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1986 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz); \
1987 const Method* meth; \
1990 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
1991 if (meth == NULL) { \
1994 va_start(args, methodID); \
1995 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \
1996 if (_isref && !dvmCheckException(ts.self())) \
1997 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2001 static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, jobject jobj,\
2002 jclass jclazz, jmethodID methodID, va_list args) \
2004 ScopedJniThreadState ts(env); \
2005 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
2006 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz); \
2007 const Method* meth; \
2009 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
2010 if (meth == NULL) { \
2013 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \
2014 if (_isref && !dvmCheckException(ts.self())) \
2015 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2018 static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, jobject jobj,\
2019 jclass jclazz, jmethodID methodID, jvalue* args) \
2021 ScopedJniThreadState ts(env); \
2022 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
2023 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz); \
2024 const Method* meth; \
2026 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
2027 if (meth == NULL) { \
2030 dvmCallMethodA(ts.self(), meth, obj, true, &result, args); \
2031 if (_isref && !dvmCheckException(ts.self())) \
2032 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2035 CALL_NONVIRTUAL(jobject, Object, NULL, (jobject) result.l, true);
2036 CALL_NONVIRTUAL(jboolean, Boolean, 0, result.z, false);
2037 CALL_NONVIRTUAL(jbyte, Byte, 0, result.b, false);
2038 CALL_NONVIRTUAL(jchar, Char, 0, result.c, false);
2039 CALL_NONVIRTUAL(jshort, Short, 0, result.s, false);
2040 CALL_NONVIRTUAL(jint, Int, 0, result.i, false);
2041 CALL_NONVIRTUAL(jlong, Long, 0, result.j, false);
2042 CALL_NONVIRTUAL(jfloat, Float, 0.0f, result.f, false);
2043 CALL_NONVIRTUAL(jdouble, Double, 0.0, result.d, false);
2044 CALL_NONVIRTUAL(void, Void, , , false);
2048 * Call a static method.
2050 #define CALL_STATIC(_ctype, _jname, _retfail, _retok, _isref) \
2051 static _ctype CallStatic##_jname##Method(JNIEnv* env, jclass jclazz, \
2052 jmethodID methodID, ...) \
2054 UNUSED_PARAMETER(jclazz); \
2055 ScopedJniThreadState ts(env); \
2058 va_start(args, methodID); \
2059 dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
2061 if (_isref && !dvmCheckException(ts.self())) \
2062 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2065 static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass jclazz, \
2066 jmethodID methodID, va_list args) \
2068 UNUSED_PARAMETER(jclazz); \
2069 ScopedJniThreadState ts(env); \
2071 dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
2072 if (_isref && !dvmCheckException(ts.self())) \
2073 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2076 static _ctype CallStatic##_jname##MethodA(JNIEnv* env, jclass jclazz, \
2077 jmethodID methodID, jvalue* args) \
2079 UNUSED_PARAMETER(jclazz); \
2080 ScopedJniThreadState ts(env); \
2082 dvmCallMethodA(ts.self(), (Method*)methodID, NULL, true, &result, args);\
2083 if (_isref && !dvmCheckException(ts.self())) \
2084 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2087 CALL_STATIC(jobject, Object, NULL, (jobject) result.l, true);
2088 CALL_STATIC(jboolean, Boolean, 0, result.z, false);
2089 CALL_STATIC(jbyte, Byte, 0, result.b, false);
2090 CALL_STATIC(jchar, Char, 0, result.c, false);
2091 CALL_STATIC(jshort, Short, 0, result.s, false);
2092 CALL_STATIC(jint, Int, 0, result.i, false);
2093 CALL_STATIC(jlong, Long, 0, result.j, false);
2094 CALL_STATIC(jfloat, Float, 0.0f, result.f, false);
2095 CALL_STATIC(jdouble, Double, 0.0, result.d, false);
2096 CALL_STATIC(void, Void, , , false);
2099 * Create a new String from Unicode data.
2101 * If "len" is zero, we will return an empty string even if "unicodeChars"
2102 * is NULL. (The JNI spec is vague here.)
2104 static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) {
2105 ScopedJniThreadState ts(env);
2106 StringObject* jstr = dvmCreateStringFromUnicode(unicodeChars, len);
2110 dvmReleaseTrackedAlloc((Object*) jstr, NULL);
2111 return (jstring) addLocalReference(ts.self(), (Object*) jstr);
2115 * Return the length of a String in Unicode character units.
2117 static jsize GetStringLength(JNIEnv* env, jstring jstr) {
2118 ScopedJniThreadState ts(env);
2119 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2120 return strObj->length();
2125 * Get a string's character data.
2127 * The result is guaranteed to be valid until ReleaseStringChars is
2128 * called, which means we have to pin it or return a copy.
2130 static const jchar* GetStringChars(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2131 ScopedJniThreadState ts(env);
2133 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2134 ArrayObject* strChars = strObj->array();
2136 pinPrimitiveArray(strChars);
2138 const u2* data = strObj->chars();
2139 if (isCopy != NULL) {
2140 *isCopy = JNI_FALSE;
2142 return (jchar*) data;
2146 * Release our grip on some characters from a string.
2148 static void ReleaseStringChars(JNIEnv* env, jstring jstr, const jchar* chars) {
2149 ScopedJniThreadState ts(env);
2150 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2151 ArrayObject* strChars = strObj->array();
2152 unpinPrimitiveArray(strChars);
2156 * Create a new java.lang.String object from chars in modified UTF-8 form.
2158 * The spec doesn't say how to handle a NULL string. Popular desktop VMs
2159 * accept it and return a NULL pointer in response.
2161 static jstring NewStringUTF(JNIEnv* env, const char* bytes) {
2162 ScopedJniThreadState ts(env);
2163 if (bytes == NULL) {
2166 /* note newStr could come back NULL on OOM */
2167 StringObject* newStr = dvmCreateStringFromCstr(bytes);
2168 jstring result = (jstring) addLocalReference(ts.self(), (Object*) newStr);
2169 dvmReleaseTrackedAlloc((Object*)newStr, NULL);
2174 * Return the length in bytes of the modified UTF-8 form of the string.
2176 static jsize GetStringUTFLength(JNIEnv* env, jstring jstr) {
2177 ScopedJniThreadState ts(env);
2178 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2179 if (strObj == NULL) {
2180 return 0; // Should we throw something or assert?
2182 return strObj->utfLength();
2186 * Convert "string" to modified UTF-8 and return a pointer. The returned
2187 * value must be released with ReleaseStringUTFChars.
2189 * According to the JNI reference, "Returns a pointer to a UTF-8 string,
2190 * or NULL if the operation fails. Returns NULL if and only if an invocation
2191 * of this function has thrown an exception."
2193 * The behavior here currently follows that of other open-source VMs, which
2194 * quietly return NULL if "string" is NULL. We should consider throwing an
2195 * NPE. (The CheckJNI code blows up if you try to pass in a NULL string,
2196 * which should catch this sort of thing during development.) Certain other
2197 * VMs will crash with a segmentation fault.
2199 static const char* GetStringUTFChars(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2200 ScopedJniThreadState ts(env);
2202 /* this shouldn't happen; throw NPE? */
2205 if (isCopy != NULL) {
2208 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2209 char* newStr = dvmCreateCstrFromString(strObj);
2210 if (newStr == NULL) {
2211 /* assume memory failure */
2212 dvmThrowOutOfMemoryError("native heap string alloc failed");
2218 * Release a string created by GetStringUTFChars().
2220 static void ReleaseStringUTFChars(JNIEnv* env, jstring jstr, const char* utf) {
2221 ScopedJniThreadState ts(env);
2226 * Return the capacity of the array.
2228 static jsize GetArrayLength(JNIEnv* env, jarray jarr) {
2229 ScopedJniThreadState ts(env);
2230 ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2231 return arrObj->length;
2235 * Construct a new array that holds objects from class "elementClass".
2237 static jobjectArray NewObjectArray(JNIEnv* env, jsize length,
2238 jclass jelementClass, jobject jinitialElement)
2240 ScopedJniThreadState ts(env);
2242 if (jelementClass == NULL) {
2243 dvmThrowNullPointerException("JNI NewObjectArray elementClass == NULL");
2247 ClassObject* elemClassObj = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jelementClass);
2248 ClassObject* arrayClass = dvmFindArrayClassForElement(elemClassObj);
2249 ArrayObject* newObj = dvmAllocArrayByClass(arrayClass, length, ALLOC_DEFAULT);
2250 if (newObj == NULL) {
2251 assert(dvmCheckException(ts.self()));
2254 jobjectArray newArray = (jobjectArray) addLocalReference(ts.self(), (Object*) newObj);
2255 dvmReleaseTrackedAlloc((Object*) newObj, NULL);
2258 * Initialize the array.
2260 if (jinitialElement != NULL) {
2261 Object* initialElement = dvmDecodeIndirectRef(ts.self(), jinitialElement);
2262 Object** arrayData = (Object**) (void*) newObj->contents;
2263 for (jsize i = 0; i < length; ++i) {
2264 arrayData[i] = initialElement;
2271 static bool checkArrayElementBounds(ArrayObject* arrayObj, jsize index) {
2272 assert(arrayObj != NULL);
2273 if (index < 0 || index >= (int) arrayObj->length) {
2274 dvmThrowArrayIndexOutOfBoundsException(arrayObj->length, index);
2281 * Get one element of an Object array.
2283 * Add the object to the local references table in case the array goes away.
2285 static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index) {
2286 ScopedJniThreadState ts(env);
2288 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2289 if (!checkArrayElementBounds(arrayObj, index)) {
2293 Object* value = ((Object**) (void*) arrayObj->contents)[index];
2294 return addLocalReference(ts.self(), value);
2298 * Set one element of an Object array.
2300 static void SetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index, jobject jobj) {
2301 ScopedJniThreadState ts(env);
2303 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2304 if (!checkArrayElementBounds(arrayObj, index)) {
2308 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
2310 if (obj != NULL && !dvmCanPutArrayElement(obj->clazz, arrayObj->clazz)) {
2311 ALOGV("Can't put a '%s'(%p) into array type='%s'(%p)",
2312 obj->clazz->descriptor, obj,
2313 arrayObj->clazz->descriptor, arrayObj);
2314 dvmThrowArrayStoreExceptionIncompatibleElement(obj->clazz, arrayObj->clazz);
2318 //ALOGV("JNI: set element %d in array %p to %p", index, array, value);
2320 dvmSetObjectArrayElement(arrayObj, index, obj);
2324 * Create a new array of primitive elements.
2326 #define NEW_PRIMITIVE_ARRAY(_artype, _jname, _typechar) \
2327 static _artype New##_jname##Array(JNIEnv* env, jsize length) { \
2328 ScopedJniThreadState ts(env); \
2329 ArrayObject* arrayObj = dvmAllocPrimitiveArray(_typechar, length, ALLOC_DEFAULT); \
2330 if (arrayObj == NULL) { \
2333 _artype result = (_artype) addLocalReference(ts.self(), (Object*) arrayObj); \
2334 dvmReleaseTrackedAlloc((Object*) arrayObj, NULL); \
2337 NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean, 'Z');
2338 NEW_PRIMITIVE_ARRAY(jbyteArray, Byte, 'B');
2339 NEW_PRIMITIVE_ARRAY(jcharArray, Char, 'C');
2340 NEW_PRIMITIVE_ARRAY(jshortArray, Short, 'S');
2341 NEW_PRIMITIVE_ARRAY(jintArray, Int, 'I');
2342 NEW_PRIMITIVE_ARRAY(jlongArray, Long, 'J');
2343 NEW_PRIMITIVE_ARRAY(jfloatArray, Float, 'F');
2344 NEW_PRIMITIVE_ARRAY(jdoubleArray, Double, 'D');
2347 * Get a pointer to a C array of primitive elements from an array object
2348 * of the matching type.
2350 * In a compacting GC, we either need to return a copy of the elements or
2351 * "pin" the memory. Otherwise we run the risk of native code using the
2352 * buffer as the destination of e.g. a blocking read() call that wakes up
2355 #define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
2356 static _ctype* Get##_jname##ArrayElements(JNIEnv* env, \
2357 _ctype##Array jarr, jboolean* isCopy) \
2359 ScopedJniThreadState ts(env); \
2360 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2361 pinPrimitiveArray(arrayObj); \
2362 _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2363 if (isCopy != NULL) { \
2364 *isCopy = JNI_FALSE; \
2370 * Release the storage locked down by the "get" function.
2372 * The spec says, "'mode' has no effect if 'elems' is not a copy of the
2373 * elements in 'array'." They apparently did not anticipate the need to
2376 #define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
2377 static void Release##_jname##ArrayElements(JNIEnv* env, \
2378 _ctype##Array jarr, _ctype* elems, jint mode) \
2380 UNUSED_PARAMETER(elems); \
2381 if (mode != JNI_COMMIT) { \
2382 ScopedJniThreadState ts(env); \
2383 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2384 unpinPrimitiveArray(arrayObj); \
2388 static void throwArrayRegionOutOfBounds(ArrayObject* arrayObj, jsize start,
2389 jsize len, const char* arrayIdentifier)
2391 dvmThrowExceptionFmt(gDvm.exArrayIndexOutOfBoundsException,
2392 "%s offset=%d length=%d %s.length=%d",
2393 arrayObj->clazz->descriptor, start, len, arrayIdentifier,
2398 * Copy a section of a primitive array to a buffer.
2400 #define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
2401 static void Get##_jname##ArrayRegion(JNIEnv* env, \
2402 _ctype##Array jarr, jsize start, jsize len, _ctype* buf) \
2404 ScopedJniThreadState ts(env); \
2405 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2406 _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2407 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
2408 throwArrayRegionOutOfBounds(arrayObj, start, len, "src"); \
2410 memcpy(buf, data + start, len * sizeof(_ctype)); \
2415 * Copy a section of a primitive array from a buffer.
2417 #define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
2418 static void Set##_jname##ArrayRegion(JNIEnv* env, \
2419 _ctype##Array jarr, jsize start, jsize len, const _ctype* buf) \
2421 ScopedJniThreadState ts(env); \
2422 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2423 _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2424 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
2425 throwArrayRegionOutOfBounds(arrayObj, start, len, "dst"); \
2427 memcpy(data + start, buf, len * sizeof(_ctype)); \
2433 * Get<Type>ArrayElements
2434 * Release<Type>ArrayElements
2435 * Get<Type>ArrayRegion
2436 * Set<Type>ArrayRegion
2438 #define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname) \
2439 GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
2440 RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
2441 GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \
2442 SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
2444 PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean);
2445 PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte);
2446 PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char);
2447 PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short);
2448 PRIMITIVE_ARRAY_FUNCTIONS(jint, Int);
2449 PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long);
2450 PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float);
2451 PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double);
2454 * Register one or more native functions in one class.
2456 * This can be called multiple times on the same method, allowing the
2457 * caller to redefine the method implementation at will.
2459 static jint RegisterNatives(JNIEnv* env, jclass jclazz,
2460 const JNINativeMethod* methods, jint nMethods)
2462 ScopedJniThreadState ts(env);
2464 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
2466 if (gDvm.verboseJni) {
2467 ALOGI("[Registering JNI native methods for class %s]",
2471 for (int i = 0; i < nMethods; i++) {
2472 if (!dvmRegisterJNIMethod(clazz, methods[i].name,
2473 methods[i].signature, methods[i].fnPtr))
2482 * Un-register all native methods associated with the class.
2484 * The JNI docs refer to this as a way to reload/relink native libraries,
2485 * and say it "should not be used in normal native code". In particular,
2486 * there is no need to do this during shutdown, and you do not need to do
2487 * this before redefining a method implementation with RegisterNatives.
2489 * It's chiefly useful for a native "plugin"-style library that wasn't
2490 * loaded with System.loadLibrary() (since there's no way to unload those).
2491 * For example, the library could upgrade itself by:
2493 * 1. call UnregisterNatives to unbind the old methods
2494 * 2. ensure that no code is still executing inside it (somehow)
2495 * 3. dlclose() the library
2496 * 4. dlopen() the new library
2497 * 5. use RegisterNatives to bind the methods from the new library
2499 * The above can work correctly without the UnregisterNatives call, but
2500 * creates a window of opportunity in which somebody might try to call a
2501 * method that is pointing at unmapped memory, crashing the VM. In theory
2502 * the same guards that prevent dlclose() from unmapping executing code could
2503 * prevent that anyway, but with this we can be more thorough and also deal
2504 * with methods that only exist in the old or new form of the library (maybe
2505 * the lib wants to try the call and catch the UnsatisfiedLinkError).
2507 static jint UnregisterNatives(JNIEnv* env, jclass jclazz) {
2508 ScopedJniThreadState ts(env);
2510 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
2511 if (gDvm.verboseJni) {
2512 ALOGI("[Unregistering JNI native methods for class %s]",
2515 dvmUnregisterJNINativeMethods(clazz);
2522 * We have to track all monitor enters and exits, so that we can undo any
2523 * outstanding synchronization before the thread exits.
2525 static jint MonitorEnter(JNIEnv* env, jobject jobj) {
2526 ScopedJniThreadState ts(env);
2527 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
2528 dvmLockObject(ts.self(), obj);
2529 trackMonitorEnter(ts.self(), obj);
2534 * Unlock the monitor.
2536 * Throws an IllegalMonitorStateException if the current thread
2537 * doesn't own the monitor. (dvmUnlockObject() takes care of the throw.)
2539 * According to the 1.6 spec, it's legal to call here with an exception
2540 * pending. If this fails, we'll stomp the original exception.
2542 static jint MonitorExit(JNIEnv* env, jobject jobj) {
2543 ScopedJniThreadState ts(env);
2544 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
2545 bool success = dvmUnlockObject(ts.self(), obj);
2547 trackMonitorExit(ts.self(), obj);
2549 return success ? JNI_OK : JNI_ERR;
2553 * Return the JavaVM interface associated with the current thread.
2555 static jint GetJavaVM(JNIEnv* env, JavaVM** vm) {
2556 ScopedJniThreadState ts(env);
2557 *vm = gDvmJni.jniVm;
2558 return (*vm == NULL) ? JNI_ERR : JNI_OK;
2562 * Copies "len" Unicode characters, from offset "start".
2564 static void GetStringRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, jchar* buf) {
2565 ScopedJniThreadState ts(env);
2566 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2567 int strLen = strObj->length();
2568 if (((start|len) < 0) || (start + len > strLen)) {
2569 dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
2572 memcpy(buf, strObj->chars() + start, len * sizeof(u2));
2576 * Translates "len" Unicode characters, from offset "start", into
2577 * modified UTF-8 encoding.
2579 static void GetStringUTFRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, char* buf) {
2580 ScopedJniThreadState ts(env);
2581 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2582 int strLen = strObj->length();
2583 if (((start|len) < 0) || (start + len > strLen)) {
2584 dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
2587 dvmGetStringUtfRegion(strObj, start, len, buf);
2591 * Get a raw pointer to array data.
2593 * The caller is expected to call "release" before doing any JNI calls
2594 * or blocking I/O operations.
2596 * We need to pin the memory or block GC.
2598 static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray jarr, jboolean* isCopy) {
2599 ScopedJniThreadState ts(env);
2600 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2601 pinPrimitiveArray(arrayObj);
2602 void* data = arrayObj->contents;
2603 if (UNLIKELY(isCopy != NULL)) {
2604 *isCopy = JNI_FALSE;
2610 * Release an array obtained with GetPrimitiveArrayCritical.
2612 static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray jarr, void* carray, jint mode) {
2613 if (mode != JNI_COMMIT) {
2614 ScopedJniThreadState ts(env);
2615 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2616 unpinPrimitiveArray(arrayObj);
2621 * Like GetStringChars, but with restricted use.
2623 static const jchar* GetStringCritical(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2624 ScopedJniThreadState ts(env);
2626 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2627 ArrayObject* strChars = strObj->array();
2629 pinPrimitiveArray(strChars);
2631 const u2* data = strObj->chars();
2632 if (isCopy != NULL) {
2633 *isCopy = JNI_FALSE;
2635 return (jchar*) data;
2639 * Like ReleaseStringChars, but with restricted use.
2641 static void ReleaseStringCritical(JNIEnv* env, jstring jstr, const jchar* carray) {
2642 ScopedJniThreadState ts(env);
2643 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2644 ArrayObject* strChars = strObj->array();
2645 unpinPrimitiveArray(strChars);
2649 * Create a new weak global reference.
2651 static jweak NewWeakGlobalRef(JNIEnv* env, jobject jobj) {
2652 ScopedJniThreadState ts(env);
2653 Object *obj = dvmDecodeIndirectRef(ts.self(), jobj);
2654 return (jweak) addWeakGlobalReference(obj);
2658 * Delete the specified weak global reference.
2660 static void DeleteWeakGlobalRef(JNIEnv* env, jweak wref) {
2661 ScopedJniThreadState ts(env);
2662 deleteWeakGlobalReference(wref);
2666 * Quick check for pending exceptions.
2668 * TODO: we should be able to skip the enter/exit macros here.
2670 static jboolean ExceptionCheck(JNIEnv* env) {
2671 ScopedJniThreadState ts(env);
2672 return dvmCheckException(ts.self());
2676 * Returns the type of the object referred to by "obj". It can be local,
2677 * global, or weak global.
2679 * In the current implementation, references can be global and local at
2680 * the same time, so while the return value is accurate it may not tell
2683 static jobjectRefType GetObjectRefType(JNIEnv* env, jobject jobj) {
2684 ScopedJniThreadState ts(env);
2685 return dvmGetJNIRefType(ts.self(), jobj);
2689 * Allocate and return a new java.nio.ByteBuffer for this block of memory.
2691 static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
2692 ScopedJniThreadState ts(env);
2695 ALOGE("JNI ERROR (app bug): negative buffer capacity: %lld", capacity);
2698 if (address == NULL && capacity != 0) {
2699 ALOGE("JNI ERROR (app bug): non-zero capacity for NULL pointer: %lld", capacity);
2703 /* create an instance of java.nio.ReadWriteDirectByteBuffer */
2704 ClassObject* bufferClazz = gDvm.classJavaNioReadWriteDirectByteBuffer;
2705 if (!dvmIsClassInitialized(bufferClazz) && !dvmInitClass(bufferClazz)) {
2708 Object* newObj = dvmAllocObject(bufferClazz, ALLOC_DONT_TRACK);
2709 if (newObj == NULL) {
2712 /* call the constructor */
2713 jobject result = addLocalReference(ts.self(), newObj);
2715 dvmCallMethod(ts.self(), gDvm.methJavaNioReadWriteDirectByteBuffer_init,
2716 newObj, &unused, (jint) address, (jint) capacity);
2717 if (dvmGetException(ts.self()) != NULL) {
2718 deleteLocalReference(ts.self(), result);
2725 * Get the starting address of the buffer for the specified java.nio.Buffer.
2727 * If this is not a "direct" buffer, we return NULL.
2729 static void* GetDirectBufferAddress(JNIEnv* env, jobject jbuf) {
2730 ScopedJniThreadState ts(env);
2732 // All Buffer objects have an effectiveDirectAddress field.
2733 Object* bufObj = dvmDecodeIndirectRef(ts.self(), jbuf);
2734 return (void*) dvmGetFieldInt(bufObj, gDvm.offJavaNioBuffer_effectiveDirectAddress);
2738 * Get the capacity of the buffer for the specified java.nio.Buffer.
2740 * Returns -1 if the object is not a direct buffer. (We actually skip
2741 * this check, since it's expensive to determine, and just return the
2742 * capacity regardless.)
2744 static jlong GetDirectBufferCapacity(JNIEnv* env, jobject jbuf) {
2745 ScopedJniThreadState ts(env);
2748 * The capacity is always in the Buffer.capacity field.
2750 * (The "check" version should verify that this is actually a Buffer,
2751 * but we're not required to do so here.)
2753 Object* buf = dvmDecodeIndirectRef(ts.self(), jbuf);
2754 return dvmGetFieldInt(buf, gDvm.offJavaNioBuffer_capacity);
2759 * ===========================================================================
2760 * JNI invocation functions
2761 * ===========================================================================
2765 * Handle AttachCurrentThread{AsDaemon}.
2767 * We need to make sure the VM is actually running. For example, if we start
2768 * up, issue an Attach, and the VM exits almost immediately, by the time the
2769 * attaching happens the VM could already be shutting down.
2771 * It's hard to avoid a race condition here because we don't want to hold
2772 * a lock across the entire operation. What we can do is temporarily
2773 * increment the thread count to prevent a VM exit.
2775 * This could potentially still have problems if a daemon thread calls here
2776 * while the VM is shutting down. dvmThreadSelf() will work, since it just
2777 * uses pthread TLS, but dereferencing "vm" could fail. Such is life when
2778 * you shut down a VM while threads are still running inside it.
2780 * Remember that some code may call this as a way to find the per-thread
2781 * JNIEnv pointer. Don't do excess work for that case.
2783 static jint attachThread(JavaVM* vm, JNIEnv** p_env, void* thr_args, bool isDaemon) {
2784 JavaVMAttachArgs* args = (JavaVMAttachArgs*) thr_args;
2787 * Return immediately if we're already one with the VM.
2789 Thread* self = dvmThreadSelf();
2791 *p_env = self->jniEnv;
2796 * No threads allowed in zygote mode.
2802 /* increment the count to keep the VM from bailing while we run */
2803 dvmLockThreadList(NULL);
2804 if (gDvm.nonDaemonThreadCount == 0) {
2806 ALOGV("Refusing to attach thread '%s' -- VM is shutting down",
2807 (thr_args == NULL) ? "(unknown)" : args->name);
2808 dvmUnlockThreadList();
2811 gDvm.nonDaemonThreadCount++;
2812 dvmUnlockThreadList();
2814 /* tweak the JavaVMAttachArgs as needed */
2815 JavaVMAttachArgs argsCopy;
2817 /* allow the v1.1 calling convention */
2818 argsCopy.version = JNI_VERSION_1_2;
2819 argsCopy.name = NULL;
2820 argsCopy.group = (jobject) dvmGetMainThreadGroup();
2822 assert(args->version >= JNI_VERSION_1_2);
2824 argsCopy.version = args->version;
2825 argsCopy.name = args->name;
2826 if (args->group != NULL) {
2827 argsCopy.group = (jobject) dvmDecodeIndirectRef(NULL, args->group);
2829 argsCopy.group = (jobject) dvmGetMainThreadGroup();
2833 bool result = dvmAttachCurrentThread(&argsCopy, isDaemon);
2835 /* restore the count */
2836 dvmLockThreadList(NULL);
2837 gDvm.nonDaemonThreadCount--;
2838 dvmUnlockThreadList();
2841 * Change the status to indicate that we're out in native code. This
2842 * call is not guarded with state-change macros, so we have to do it
2846 self = dvmThreadSelf();
2847 assert(self != NULL);
2848 dvmChangeStatus(self, THREAD_NATIVE);
2849 *p_env = self->jniEnv;
2857 * Attach the current thread to the VM. If the thread is already attached,
2860 static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
2861 return attachThread(vm, p_env, thr_args, false);
2865 * Like AttachCurrentThread, but set the "daemon" flag.
2867 static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args)
2869 return attachThread(vm, p_env, thr_args, true);
2873 * Dissociate the current thread from the VM.
2875 static jint DetachCurrentThread(JavaVM* vm) {
2876 Thread* self = dvmThreadSelf();
2878 /* not attached, can't do anything */
2882 /* switch to "running" to check for suspension */
2883 dvmChangeStatus(self, THREAD_RUNNING);
2885 /* detach the thread */
2886 dvmDetachCurrentThread();
2888 /* (no need to change status back -- we have no status) */
2893 * If current thread is attached to VM, return the associated JNIEnv.
2894 * Otherwise, stuff NULL in and return JNI_EDETACHED.
2896 * JVMTI overloads this by specifying a magic value for "version", so we
2897 * do want to check that here.
2899 static jint GetEnv(JavaVM* vm, void** env, jint version) {
2900 Thread* self = dvmThreadSelf();
2902 if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6) {
2903 return JNI_EVERSION;
2909 /* TODO: status change is probably unnecessary */
2910 dvmChangeStatus(self, THREAD_RUNNING);
2911 *env = (void*) dvmGetThreadJNIEnv(self);
2912 dvmChangeStatus(self, THREAD_NATIVE);
2914 return (*env != NULL) ? JNI_OK : JNI_EDETACHED;
2918 * Destroy the VM. This may be called from any thread.
2920 * If the current thread is attached, wait until the current thread is
2921 * the only non-daemon user-level thread. If the current thread is not
2922 * attached, we attach it and do the processing as usual. (If the attach
2923 * fails, it's probably because all the non-daemon threads have already
2924 * exited and the VM doesn't want to let us back in.)
2926 * TODO: we don't really deal with the situation where more than one thread
2927 * has called here. One thread wins, the other stays trapped waiting on
2928 * the condition variable forever. Not sure this situation is interesting
2931 static jint DestroyJavaVM(JavaVM* vm) {
2932 JavaVMExt* ext = (JavaVMExt*) vm;
2937 if (gDvm.verboseShutdown) {
2938 ALOGD("DestroyJavaVM waiting for non-daemon threads to exit");
2942 * Sleep on a condition variable until it's okay to exit.
2944 Thread* self = dvmThreadSelf();
2947 if (AttachCurrentThread(vm, &tmpEnv, NULL) != JNI_OK) {
2948 ALOGV("Unable to reattach main for Destroy; assuming VM is shutting down (count=%d)",
2949 gDvm.nonDaemonThreadCount);
2952 ALOGV("Attached to wait for shutdown in Destroy");
2955 dvmChangeStatus(self, THREAD_VMWAIT);
2957 dvmLockThreadList(self);
2958 gDvm.nonDaemonThreadCount--; // remove current thread from count
2960 while (gDvm.nonDaemonThreadCount > 0) {
2961 pthread_cond_wait(&gDvm.vmExitCond, &gDvm.threadListLock);
2964 dvmUnlockThreadList();
2968 // TODO: call System.exit() to run any registered shutdown hooks
2969 // (this may not return -- figure out how this should work)
2971 if (gDvm.verboseShutdown) {
2972 ALOGD("DestroyJavaVM shutting VM down");
2976 // TODO - free resources associated with JNI-attached daemon threads
2985 * ===========================================================================
2987 * ===========================================================================
2990 static const struct JNINativeInterface gNativeInterface = {
3001 FromReflectedMethod,
3025 EnsureLocalCapacity,
3068 CallNonvirtualObjectMethod,
3069 CallNonvirtualObjectMethodV,
3070 CallNonvirtualObjectMethodA,
3071 CallNonvirtualBooleanMethod,
3072 CallNonvirtualBooleanMethodV,
3073 CallNonvirtualBooleanMethodA,
3074 CallNonvirtualByteMethod,
3075 CallNonvirtualByteMethodV,
3076 CallNonvirtualByteMethodA,
3077 CallNonvirtualCharMethod,
3078 CallNonvirtualCharMethodV,
3079 CallNonvirtualCharMethodA,
3080 CallNonvirtualShortMethod,
3081 CallNonvirtualShortMethodV,
3082 CallNonvirtualShortMethodA,
3083 CallNonvirtualIntMethod,
3084 CallNonvirtualIntMethodV,
3085 CallNonvirtualIntMethodA,
3086 CallNonvirtualLongMethod,
3087 CallNonvirtualLongMethodV,
3088 CallNonvirtualLongMethodA,
3089 CallNonvirtualFloatMethod,
3090 CallNonvirtualFloatMethodV,
3091 CallNonvirtualFloatMethodA,
3092 CallNonvirtualDoubleMethod,
3093 CallNonvirtualDoubleMethodV,
3094 CallNonvirtualDoubleMethodA,
3095 CallNonvirtualVoidMethod,
3096 CallNonvirtualVoidMethodV,
3097 CallNonvirtualVoidMethodA,
3122 CallStaticObjectMethod,
3123 CallStaticObjectMethodV,
3124 CallStaticObjectMethodA,
3125 CallStaticBooleanMethod,
3126 CallStaticBooleanMethodV,
3127 CallStaticBooleanMethodA,
3128 CallStaticByteMethod,
3129 CallStaticByteMethodV,
3130 CallStaticByteMethodA,
3131 CallStaticCharMethod,
3132 CallStaticCharMethodV,
3133 CallStaticCharMethodA,
3134 CallStaticShortMethod,
3135 CallStaticShortMethodV,
3136 CallStaticShortMethodA,
3137 CallStaticIntMethod,
3138 CallStaticIntMethodV,
3139 CallStaticIntMethodA,
3140 CallStaticLongMethod,
3141 CallStaticLongMethodV,
3142 CallStaticLongMethodA,
3143 CallStaticFloatMethod,
3144 CallStaticFloatMethodV,
3145 CallStaticFloatMethodA,
3146 CallStaticDoubleMethod,
3147 CallStaticDoubleMethodV,
3148 CallStaticDoubleMethodA,
3149 CallStaticVoidMethod,
3150 CallStaticVoidMethodV,
3151 CallStaticVoidMethodA,
3155 GetStaticObjectField,
3156 GetStaticBooleanField,
3159 GetStaticShortField,
3162 GetStaticFloatField,
3163 GetStaticDoubleField,
3165 SetStaticObjectField,
3166 SetStaticBooleanField,
3169 SetStaticShortField,
3172 SetStaticFloatField,
3173 SetStaticDoubleField,
3184 ReleaseStringUTFChars,
3188 GetObjectArrayElement,
3189 SetObjectArrayElement,
3200 GetBooleanArrayElements,
3201 GetByteArrayElements,
3202 GetCharArrayElements,
3203 GetShortArrayElements,
3204 GetIntArrayElements,
3205 GetLongArrayElements,
3206 GetFloatArrayElements,
3207 GetDoubleArrayElements,
3209 ReleaseBooleanArrayElements,
3210 ReleaseByteArrayElements,
3211 ReleaseCharArrayElements,
3212 ReleaseShortArrayElements,
3213 ReleaseIntArrayElements,
3214 ReleaseLongArrayElements,
3215 ReleaseFloatArrayElements,
3216 ReleaseDoubleArrayElements,
3218 GetBooleanArrayRegion,
3221 GetShortArrayRegion,
3224 GetFloatArrayRegion,
3225 GetDoubleArrayRegion,
3226 SetBooleanArrayRegion,
3229 SetShortArrayRegion,
3232 SetFloatArrayRegion,
3233 SetDoubleArrayRegion,
3246 GetPrimitiveArrayCritical,
3247 ReleasePrimitiveArrayCritical,
3250 ReleaseStringCritical,
3253 DeleteWeakGlobalRef,
3257 NewDirectByteBuffer,
3258 GetDirectBufferAddress,
3259 GetDirectBufferCapacity,
3264 static const struct JNIInvokeInterface gInvokeInterface = {
3270 AttachCurrentThread,
3271 DetachCurrentThread,
3275 AttachCurrentThreadAsDaemon,
3279 * ===========================================================================
3281 * ===========================================================================
3285 * Create a new JNIEnv struct and add it to the VM's list.
3287 * "self" will be NULL for the main thread, since the VM hasn't started
3288 * yet; the value will be filled in later.
3290 JNIEnv* dvmCreateJNIEnv(Thread* self) {
3291 JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
3294 // ALOGI("Ent CreateJNIEnv: threadid=%d %p", self->threadId, self);
3298 JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
3299 newEnv->funcTable = &gNativeInterface;
3301 dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
3302 assert(newEnv->envThreadId != 0);
3304 /* make it obvious if we fail to initialize these later */
3305 newEnv->envThreadId = 0x77777775;
3306 newEnv->self = (Thread*) 0x77777779;
3308 if (gDvmJni.useCheckJni) {
3309 dvmUseCheckedJniEnv(newEnv);
3312 ScopedPthreadMutexLock lock(&vm->envListLock);
3314 /* insert at head of list */
3315 newEnv->next = vm->envList;
3316 assert(newEnv->prev == NULL);
3317 if (vm->envList == NULL) {
3318 // rare, but possible
3319 vm->envList = newEnv;
3321 vm->envList->prev = newEnv;
3323 vm->envList = newEnv;
3326 // ALOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self);
3327 return (JNIEnv*) newEnv;
3331 * Remove a JNIEnv struct from the list and free it.
3333 void dvmDestroyJNIEnv(JNIEnv* env) {
3338 //ALOGI("Ent DestroyJNIEnv: threadid=%d %p", self->threadId, self);
3340 JNIEnvExt* extEnv = (JNIEnvExt*) env;
3341 JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
3343 ScopedPthreadMutexLock lock(&vm->envListLock);
3345 if (extEnv == vm->envList) {
3346 assert(extEnv->prev == NULL);
3347 vm->envList = extEnv->next;
3349 assert(extEnv->prev != NULL);
3350 extEnv->prev->next = extEnv->next;
3352 if (extEnv->next != NULL) {
3353 extEnv->next->prev = extEnv->prev;
3357 //ALOGI("Xit DestroyJNIEnv: threadid=%d %p", self->threadId, self);
3361 * Enable "checked JNI" after the VM has partially started. This must
3362 * only be called in "zygote" mode, when we have one thread running.
3364 * This doesn't attempt to rewrite the JNI call bridge associated with
3365 * native methods, so we won't get those checks for any methods that have
3366 * already been resolved.
3368 void dvmLateEnableCheckedJni() {
3369 JNIEnvExt* extEnv = dvmGetJNIEnvForThread();
3370 if (extEnv == NULL) {
3371 ALOGE("dvmLateEnableCheckedJni: thread has no JNIEnv");
3374 JavaVMExt* extVm = (JavaVMExt*) gDvmJni.jniVm;
3375 assert(extVm != NULL);
3377 if (!gDvmJni.useCheckJni) {
3378 ALOGD("Late-enabling CheckJNI");
3379 dvmUseCheckedJniVm(extVm);
3380 dvmUseCheckedJniEnv(extEnv);
3382 ALOGD("Not late-enabling CheckJNI (already on)");
3389 jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
3394 * Return a buffer full of created VMs.
3396 * We always have zero or one.
3398 jint JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs) {
3399 if (gDvmJni.jniVm != NULL) {
3402 *vmBuf++ = gDvmJni.jniVm;
3411 * Create a new VM instance.
3413 * The current thread becomes the main VM thread. We return immediately,
3414 * which effectively means the caller is executing in a native method.
3416 jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
3417 const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args;
3418 if (args->version < JNI_VERSION_1_2) {
3419 return JNI_EVERSION;
3422 // TODO: don't allow creation of multiple VMs -- one per customer for now
3424 /* zero globals; not strictly necessary the first time a VM is started */
3425 memset(&gDvm, 0, sizeof(gDvm));
3428 * Set up structures for JNIEnv and VM.
3430 JavaVMExt* pVM = (JavaVMExt*) calloc(1, sizeof(JavaVMExt));
3431 pVM->funcTable = &gInvokeInterface;
3432 pVM->envList = NULL;
3433 dvmInitMutex(&pVM->envListLock);
3435 UniquePtr<const char*[]> argv(new const char*[args->nOptions]);
3436 memset(argv.get(), 0, sizeof(char*) * (args->nOptions));
3439 * Convert JNI args to argv.
3441 * We have to pull out vfprintf/exit/abort, because they use the
3442 * "extraInfo" field to pass function pointer "hooks" in. We also
3443 * look for the -Xcheck:jni stuff here.
3446 for (int i = 0; i < args->nOptions; i++) {
3447 const char* optStr = args->options[i].optionString;
3448 if (optStr == NULL) {
3449 dvmFprintf(stderr, "ERROR: CreateJavaVM failed: argument %d was NULL\n", i);
3451 } else if (strcmp(optStr, "vfprintf") == 0) {
3452 gDvm.vfprintfHook = (int (*)(FILE *, const char*, va_list))args->options[i].extraInfo;
3453 } else if (strcmp(optStr, "exit") == 0) {
3454 gDvm.exitHook = (void (*)(int)) args->options[i].extraInfo;
3455 } else if (strcmp(optStr, "abort") == 0) {
3456 gDvm.abortHook = (void (*)(void))args->options[i].extraInfo;
3457 } else if (strcmp(optStr, "sensitiveThread") == 0) {
3458 gDvm.isSensitiveThreadHook = (bool (*)(void))args->options[i].extraInfo;
3459 } else if (strcmp(optStr, "-Xcheck:jni") == 0) {
3460 gDvmJni.useCheckJni = true;
3461 } else if (strncmp(optStr, "-Xjniopts:", 10) == 0) {
3462 char* jniOpts = strdup(optStr + 10);
3463 size_t jniOptCount = 1;
3464 for (char* p = jniOpts; *p != 0; ++p) {
3470 char* jniOpt = jniOpts;
3471 for (size_t i = 0; i < jniOptCount; ++i) {
3472 if (strcmp(jniOpt, "warnonly") == 0) {
3473 gDvmJni.warnOnly = true;
3474 } else if (strcmp(jniOpt, "forcecopy") == 0) {
3475 gDvmJni.forceCopy = true;
3476 } else if (strcmp(jniOpt, "logThirdPartyJni") == 0) {
3477 gDvmJni.logThirdPartyJni = true;
3479 dvmFprintf(stderr, "ERROR: CreateJavaVM failed: unknown -Xjniopts option '%s'\n",
3483 jniOpt += strlen(jniOpt) + 1;
3487 /* regular option */
3488 argv[argc++] = optStr;
3492 if (gDvmJni.useCheckJni) {
3493 dvmUseCheckedJniVm(pVM);
3496 if (gDvmJni.jniVm != NULL) {
3497 dvmFprintf(stderr, "ERROR: Dalvik only supports one VM per process\n");
3500 gDvmJni.jniVm = (JavaVM*) pVM;
3503 * Create a JNIEnv for the main thread. We need to have something set up
3504 * here because some of the class initialization we do when starting
3505 * up the VM will call into native code.
3507 JNIEnvExt* pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);
3509 /* Initialize VM. */
3510 gDvm.initializing = true;
3511 std::string status =
3512 dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);
3513 gDvm.initializing = false;
3515 if (!status.empty()) {
3518 ALOGW("CreateJavaVM failed: %s", status.c_str());
3523 * Success! Return stuff to caller.
3525 dvmChangeStatus(NULL, THREAD_NATIVE);
3526 *p_env = (JNIEnv*) pEnv;
3527 *p_vm = (JavaVM*) pVM;
3528 ALOGV("CreateJavaVM succeeded");