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 #ifdef WITH_JNI_STACK_CHECK
138 # define COMPUTE_STACK_SUM(_self) computeStackSum(_self);
139 # define CHECK_STACK_SUM(_self) checkStackSum(_self);
142 * Compute a CRC on the entire interpreted stack.
144 * Would be nice to compute it on "self" as well, but there are parts of
145 * the Thread that can be altered by other threads (e.g. prev/next pointers).
147 static void computeStackSum(Thread* self) {
148 const u1* low = (const u1*)SAVEAREA_FROM_FP(self->interpSave.curFrame);
149 u4 crc = dvmInitCrc32();
151 crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
152 self->stackCrc = crc;
156 * Compute a CRC on the entire interpreted stack, and compare it to what
157 * we previously computed.
159 * We can execute JNI directly from native code without calling in from
160 * interpreted code during VM initialization and immediately after JNI
161 * thread attachment. Another opportunity exists during JNI_OnLoad. Rather
162 * than catching these cases we just ignore them here, which is marginally
163 * less accurate but reduces the amount of code we have to touch with #ifdefs.
165 static void checkStackSum(Thread* self) {
166 const u1* low = (const u1*)SAVEAREA_FROM_FP(self->interpSave.curFrame);
167 u4 stackCrc = self->stackCrc;
169 u4 crc = dvmInitCrc32();
170 crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
171 if (crc != stackCrc) {
172 const Method* meth = dvmGetCurrentJNIMethod();
173 if (dvmComputeExactFrameDepth(self->interpSave.curFrame) == 1) {
174 LOGD("JNI: bad stack CRC (0x%08x) -- okay during init", stackCrc);
175 } else if (strcmp(meth->name, "nativeLoad") == 0 &&
176 (strcmp(meth->clazz->descriptor, "Ljava/lang/Runtime;") == 0)) {
177 LOGD("JNI: bad stack CRC (0x%08x) -- okay during JNI_OnLoad", stackCrc);
179 LOGW("JNI: bad stack CRC (%08x vs %08x)", crc, stackCrc);
183 self->stackCrc = (u4) -1; /* make logic errors more noticeable */
187 # define COMPUTE_STACK_SUM(_self) ((void)0)
188 # define CHECK_STACK_SUM(_self) ((void)0)
193 * ===========================================================================
195 * ===========================================================================
199 * Entry/exit processing for all JNI calls.
201 * We skip the (curiously expensive) thread-local storage lookup on our Thread*.
202 * If the caller has passed the wrong JNIEnv in, we're going to be accessing unsynchronized
203 * structures from more than one thread, and things are going to fail
204 * in bizarre ways. This is only sensible if the native code has been
205 * fully exercised with CheckJNI enabled.
207 class ScopedJniThreadState {
209 explicit ScopedJniThreadState(JNIEnv* env) {
210 mSelf = ((JNIEnvExt*) env)->self;
212 if (UNLIKELY(gDvmJni.workAroundAppJniBugs)) {
213 // When emulating direct pointers with indirect references, it's critical
214 // that we use the correct per-thread indirect reference table.
215 Thread* self = gDvmJni.workAroundAppJniBugs ? dvmThreadSelf() : mSelf;
217 LOGE("JNI ERROR: env->self != thread-self (%p vs. %p); auto-correcting", mSelf, self);
222 CHECK_STACK_SUM(mSelf);
223 dvmChangeStatus(mSelf, THREAD_RUNNING);
226 ~ScopedJniThreadState() {
227 dvmChangeStatus(mSelf, THREAD_NATIVE);
228 COMPUTE_STACK_SUM(mSelf);
231 inline Thread* self() {
238 // Disallow copy and assignment.
239 ScopedJniThreadState(const ScopedJniThreadState&);
240 void operator=(const ScopedJniThreadState&);
243 #define kGlobalRefsTableInitialSize 512
244 #define kGlobalRefsTableMaxSize 51200 /* arbitrary, must be < 64K */
245 #define kGrefWaterInterval 100
246 #define kTrackGrefUsage true
248 #define kWeakGlobalRefsTableInitialSize 16
250 #define kPinTableInitialSize 16
251 #define kPinTableMaxSize 1024
252 #define kPinComplainThreshold 10
254 bool dvmJniStartup() {
255 if (!gDvm.jniGlobalRefTable.init(kGlobalRefsTableInitialSize,
256 kGlobalRefsTableMaxSize,
257 kIndirectKindGlobal)) {
260 if (!gDvm.jniWeakGlobalRefTable.init(kWeakGlobalRefsTableInitialSize,
261 kGlobalRefsTableMaxSize,
262 kIndirectKindWeakGlobal)) {
266 dvmInitMutex(&gDvm.jniGlobalRefLock);
267 dvmInitMutex(&gDvm.jniWeakGlobalRefLock);
268 gDvm.jniGlobalRefLoMark = 0;
269 gDvm.jniGlobalRefHiMark = kGrefWaterInterval * 2;
271 if (!dvmInitReferenceTable(&gDvm.jniPinRefTable, kPinTableInitialSize, kPinTableMaxSize)) {
275 dvmInitMutex(&gDvm.jniPinRefLock);
280 void dvmJniShutdown() {
281 gDvm.jniGlobalRefTable.destroy();
282 gDvm.jniWeakGlobalRefTable.destroy();
283 dvmClearReferenceTable(&gDvm.jniPinRefTable);
287 * Find the JNIEnv associated with the current thread.
289 * Currently stored in the Thread struct. Could also just drop this into
290 * thread-local storage.
292 JNIEnvExt* dvmGetJNIEnvForThread() {
293 Thread* self = dvmThreadSelf();
297 return (JNIEnvExt*) dvmGetThreadJNIEnv(self);
301 * Convert an indirect reference to an Object reference. The indirect
302 * reference may be local, global, or weak-global.
304 * If "jobj" is NULL, or is a weak global reference whose reference has
305 * been cleared, this returns NULL. If jobj is an invalid indirect
306 * reference, kInvalidIndirectRefObject is returned.
308 * Note "env" may be NULL when decoding global references.
310 Object* dvmDecodeIndirectRef(Thread* self, jobject jobj) {
315 switch (indirectRefKind(jobj)) {
316 case kIndirectKindLocal:
318 Object* result = self->jniLocalRefTable.get(jobj);
319 if (UNLIKELY(result == NULL)) {
320 LOGE("JNI ERROR (app bug): use of deleted local reference (%p)", jobj);
325 case kIndirectKindGlobal:
327 // TODO: find a way to avoid the mutex activity here
328 IndirectRefTable* pRefTable = &gDvm.jniGlobalRefTable;
329 ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
330 Object* result = pRefTable->get(jobj);
331 if (UNLIKELY(result == NULL)) {
332 LOGE("JNI ERROR (app bug): use of deleted global reference (%p)", jobj);
337 case kIndirectKindWeakGlobal:
339 // TODO: find a way to avoid the mutex activity here
340 IndirectRefTable* pRefTable = &gDvm.jniWeakGlobalRefTable;
341 ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
342 Object* result = pRefTable->get(jobj);
343 if (result == kClearedJniWeakGlobal) {
345 } else if (UNLIKELY(result == NULL)) {
346 LOGE("JNI ERROR (app bug): use of deleted weak global reference (%p)", jobj);
351 case kIndirectKindInvalid:
353 if (UNLIKELY(gDvmJni.workAroundAppJniBugs)) {
354 // Assume an invalid local reference is actually a direct pointer.
355 return reinterpret_cast<Object*>(jobj);
357 LOGW("Invalid indirect reference %p in decodeIndirectRef", jobj);
359 return kInvalidIndirectRefObject;
363 static void AddLocalReferenceFailure(IndirectRefTable* pRefTable) {
364 pRefTable->dump("JNI local");
365 LOGE("Failed adding to JNI local ref table (has %zd entries)", pRefTable->capacity());
366 dvmDumpThread(dvmThreadSelf(), false);
367 dvmAbort(); // spec says call FatalError; this is equivalent
371 * Add a local reference for an object to the current stack frame. When
372 * the native function returns, the reference will be discarded.
374 * We need to allow the same reference to be added multiple times.
376 * This will be called on otherwise unreferenced objects. We cannot do
377 * GC allocations here, and it's best if we don't grab a mutex.
379 static inline jobject addLocalReference(Thread* self, Object* obj) {
384 IndirectRefTable* pRefTable = &self->jniLocalRefTable;
385 void* curFrame = self->interpSave.curFrame;
386 u4 cookie = SAVEAREA_FROM_FP(curFrame)->xtra.localRefCookie;
387 jobject jobj = (jobject) pRefTable->add(cookie, obj);
388 if (UNLIKELY(jobj == NULL)) {
389 AddLocalReferenceFailure(pRefTable);
391 if (UNLIKELY(gDvmJni.workAroundAppJniBugs)) {
392 // Hand out direct pointers to support broken old apps.
393 return reinterpret_cast<jobject>(obj);
399 * Ensure that at least "capacity" references can be held in the local
400 * refs table of the current thread.
402 static bool ensureLocalCapacity(Thread* self, int capacity) {
403 int numEntries = self->jniLocalRefTable.capacity();
404 // TODO: this isn't quite right, since "numEntries" includes holes
405 return ((kJniLocalRefMax - numEntries) >= capacity);
409 * Explicitly delete a reference from the local list.
411 static void deleteLocalReference(Thread* self, jobject jobj) {
416 IndirectRefTable* pRefTable = &self->jniLocalRefTable;
417 void* curFrame = self->interpSave.curFrame;
418 u4 cookie = SAVEAREA_FROM_FP(curFrame)->xtra.localRefCookie;
419 if (!pRefTable->remove(cookie, jobj)) {
421 * Attempting to delete a local reference that is not in the
422 * topmost local reference frame is a no-op. DeleteLocalRef returns
423 * void and doesn't throw any exceptions, but we should probably
424 * complain about it so the user will notice that things aren't
425 * going quite the way they expect.
427 LOGW("JNI WARNING: DeleteLocalRef(%p) failed to find entry", jobj);
432 * Add a global reference for an object.
434 * We may add the same object more than once. Add/remove calls are paired,
435 * so it needs to appear on the list multiple times.
437 static jobject addGlobalReference(Object* obj) {
442 //LOGI("adding obj=%p", obj);
443 //dvmDumpThread(dvmThreadSelf(), false);
445 if (false && dvmIsClassObject((Object*)obj)) {
446 ClassObject* clazz = (ClassObject*) obj;
448 LOGI("Adding global ref on class %s", clazz->descriptor);
449 dvmDumpThread(dvmThreadSelf(), false);
451 if (false && ((Object*)obj)->clazz == gDvm.classJavaLangString) {
452 StringObject* strObj = (StringObject*) obj;
453 char* str = dvmCreateCstrFromString(strObj);
454 if (strcmp(str, "sync-response") == 0) {
456 LOGI("Adding global ref on string '%s'", str);
457 dvmDumpThread(dvmThreadSelf(), false);
462 if (false && ((Object*)obj)->clazz == gDvm.classArrayByte) {
463 ArrayObject* arrayObj = (ArrayObject*) obj;
464 if (arrayObj->length == 8192 /*&&
465 dvmReferenceTableEntries(&gDvm.jniGlobalRefTable) > 400*/)
467 LOGI("Adding global ref on byte array %p (len=%d)",
468 arrayObj, arrayObj->length);
469 dvmDumpThread(dvmThreadSelf(), false);
473 ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
476 * Throwing an exception on failure is problematic, because JNI code
477 * may not be expecting an exception, and things sort of cascade. We
478 * want to have a hard limit to catch leaks during debugging, but this
479 * otherwise needs to expand until memory is consumed. As a practical
480 * matter, if we have many thousands of global references, chances are
481 * we're either leaking global ref table entries or we're going to
482 * run out of space in the GC heap.
484 jobject jobj = (jobject) gDvm.jniGlobalRefTable.add(IRT_FIRST_SEGMENT, obj);
486 gDvm.jniGlobalRefTable.dump("JNI global");
487 LOGE("Failed adding to JNI global ref table (%zd entries)",
488 gDvm.jniGlobalRefTable.capacity());
492 LOGVV("GREF add %p (%s.%s)", obj,
493 dvmGetCurrentJNIMethod()->clazz->descriptor,
494 dvmGetCurrentJNIMethod()->name);
496 /* GREF usage tracking; should probably be disabled for production env */
497 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
498 int count = gDvm.jniGlobalRefTable.capacity();
499 // TODO: adjust for "holes"
500 if (count > gDvm.jniGlobalRefHiMark) {
501 LOGD("GREF has increased to %d", count);
502 gDvm.jniGlobalRefHiMark += kGrefWaterInterval;
503 gDvm.jniGlobalRefLoMark += kGrefWaterInterval;
505 /* watch for "excessive" use; not generally appropriate */
506 if (count >= gDvm.jniGrefLimit) {
507 if (gDvmJni.warnOnly) {
508 LOGW("Excessive JNI global references (%d)", count);
510 gDvm.jniGlobalRefTable.dump("JNI global");
511 LOGE("Excessive JNI global references (%d)", count);
520 static jobject addWeakGlobalReference(Object* obj) {
525 ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
526 IndirectRefTable *table = &gDvm.jniWeakGlobalRefTable;
527 jobject jobj = (jobject) table->add(IRT_FIRST_SEGMENT, obj);
529 gDvm.jniWeakGlobalRefTable.dump("JNI weak global");
530 LOGE("Failed adding to JNI weak global ref table (%zd entries)", table->capacity());
536 static void deleteWeakGlobalReference(jobject jobj) {
541 ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
542 IndirectRefTable *table = &gDvm.jniWeakGlobalRefTable;
543 if (!table->remove(IRT_FIRST_SEGMENT, jobj)) {
544 LOGW("JNI: DeleteWeakGlobalRef(%p) failed to find entry", jobj);
549 * Remove a global reference. In most cases it's the entry most recently
550 * added, which makes this pretty quick.
552 * Thought: if it's not the most recent entry, just null it out. When we
553 * fill up, do a compaction pass before we expand the list.
555 static void deleteGlobalReference(jobject jobj) {
560 ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
561 if (!gDvm.jniGlobalRefTable.remove(IRT_FIRST_SEGMENT, jobj)) {
562 LOGW("JNI: DeleteGlobalRef(%p) failed to find entry", jobj);
566 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
567 int count = gDvm.jniGlobalRefTable.capacity();
568 // TODO: not quite right, need to subtract holes
569 if (count < gDvm.jniGlobalRefLoMark) {
570 LOGD("GREF has decreased to %d", count);
571 gDvm.jniGlobalRefHiMark -= kGrefWaterInterval;
572 gDvm.jniGlobalRefLoMark -= kGrefWaterInterval;
578 * Objects don't currently move, so we just need to create a reference
579 * that will ensure the array object isn't collected.
581 * We use a separate reference table, which is part of the GC root set.
583 static void pinPrimitiveArray(ArrayObject* arrayObj) {
584 if (arrayObj == NULL) {
588 ScopedPthreadMutexLock lock(&gDvm.jniPinRefLock);
590 if (!dvmAddToReferenceTable(&gDvm.jniPinRefTable, (Object*)arrayObj)) {
591 dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
592 LOGE("Failed adding to JNI pinned array ref table (%d entries)",
593 (int) dvmReferenceTableEntries(&gDvm.jniPinRefTable));
594 dvmDumpThread(dvmThreadSelf(), false);
599 * If we're watching global ref usage, also keep an eye on these.
601 * The total number of pinned primitive arrays should be pretty small.
602 * A single array should not be pinned more than once or twice; any
603 * more than that is a strong indicator that a Release function is
606 if (kTrackGrefUsage && gDvm.jniGrefLimit != 0) {
608 Object** ppObj = gDvm.jniPinRefTable.table;
609 while (ppObj < gDvm.jniPinRefTable.nextEntry) {
610 if (*ppObj++ == (Object*) arrayObj)
614 if (count > kPinComplainThreshold) {
615 LOGW("JNI: pin count on array %p (%s) is now %d",
616 arrayObj, arrayObj->clazz->descriptor, count);
623 * Un-pin the array object. If an object was pinned twice, it must be
624 * unpinned twice before it's free to move.
626 static void unpinPrimitiveArray(ArrayObject* arrayObj) {
627 if (arrayObj == NULL) {
631 ScopedPthreadMutexLock lock(&gDvm.jniPinRefLock);
632 if (!dvmRemoveFromReferenceTable(&gDvm.jniPinRefTable,
633 gDvm.jniPinRefTable.table, (Object*) arrayObj))
635 LOGW("JNI: unpinPrimitiveArray(%p) failed to find entry (valid=%d)",
636 arrayObj, dvmIsHeapAddress((Object*) arrayObj));
642 * Dump the contents of the JNI reference tables to the log file.
644 * We only dump the local refs associated with the current thread.
646 void dvmDumpJniReferenceTables() {
647 Thread* self = dvmThreadSelf();
648 self->jniLocalRefTable.dump("JNI local");
649 gDvm.jniGlobalRefTable.dump("JNI global");
650 dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
654 * Verify that a reference passed in from native code is one that the
655 * code is allowed to have.
657 * It's okay for native code to pass us a reference that:
658 * - was passed in as an argument when invoked by native code (and hence
659 * is in the JNI local refs table)
660 * - was returned to it from JNI (and is now in the local refs table)
661 * - is present in the JNI global refs table
663 * Used by -Xcheck:jni and GetObjectRefType.
665 jobjectRefType dvmGetJNIRefType(Thread* self, jobject jobj) {
667 * IndirectRefKind is currently defined as an exact match of
668 * jobjectRefType, so this is easy. We have to decode it to determine
669 * if it's a valid reference and not merely valid-looking.
671 assert(jobj != NULL);
673 Object* obj = dvmDecodeIndirectRef(self, jobj);
674 if (obj == reinterpret_cast<Object*>(jobj) && gDvmJni.workAroundAppJniBugs) {
675 // If we're handing out direct pointers, check whether 'jobj' is a direct reference
676 // to a local reference.
677 return self->jniLocalRefTable.contains(obj) ? JNILocalRefType : JNIInvalidRefType;
678 } else if (obj == kInvalidIndirectRefObject) {
679 return JNIInvalidRefType;
681 return (jobjectRefType) indirectRefKind(jobj);
685 static void dumpMethods(Method* methods, size_t methodCount, const char* name) {
687 for (i = 0; i < methodCount; ++i) {
688 Method* method = &methods[i];
689 if (strcmp(name, method->name) == 0) {
690 char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
691 LOGE("Candidate: %s.%s:%s", method->clazz->descriptor, name, desc);
697 static void dumpCandidateMethods(ClassObject* clazz, const char* methodName, const char* signature) {
698 LOGE("ERROR: couldn't find native method");
699 LOGE("Requested: %s.%s:%s", clazz->descriptor, methodName, signature);
700 dumpMethods(clazz->virtualMethods, clazz->virtualMethodCount, methodName);
701 dumpMethods(clazz->directMethods, clazz->directMethodCount, methodName);
705 * Register a method that uses JNI calling conventions.
707 static bool dvmRegisterJNIMethod(ClassObject* clazz, const char* methodName,
708 const char* signature, void* fnPtr)
714 // If a signature starts with a '!', we take that as a sign that the native code doesn't
715 // need the extra JNI arguments (the JNIEnv* and the jclass).
716 bool fastJni = false;
717 if (*signature == '!') {
720 ALOGV("fast JNI method %s.%s:%s detected", clazz->descriptor, methodName, signature);
723 Method* method = dvmFindDirectMethodByDescriptor(clazz, methodName, signature);
724 if (method == NULL) {
725 method = dvmFindVirtualMethodByDescriptor(clazz, methodName, signature);
727 if (method == NULL) {
728 dumpCandidateMethods(clazz, methodName, signature);
732 if (!dvmIsNativeMethod(method)) {
733 LOGW("Unable to register: not native: %s.%s:%s", clazz->descriptor, methodName, signature);
738 // In this case, we have extra constraints to check...
739 if (dvmIsSynchronizedMethod(method)) {
740 // Synchronization is usually provided by the JNI bridge,
741 // but we won't have one.
742 LOGE("fast JNI method %s.%s:%s cannot be synchronized",
743 clazz->descriptor, methodName, signature);
746 if (!dvmIsStaticMethod(method)) {
747 // There's no real reason for this constraint, but since we won't
748 // be supplying a JNIEnv* or a jobject 'this', you're effectively
749 // static anyway, so it seems clearer to say so.
750 LOGE("fast JNI method %s.%s:%s cannot be non-static",
751 clazz->descriptor, methodName, signature);
756 if (method->nativeFunc != dvmResolveNativeMethod) {
757 /* this is allowed, but unusual */
758 ALOGV("Note: %s.%s:%s was already registered", clazz->descriptor, methodName, signature);
761 method->fastJni = fastJni;
762 dvmUseJNIBridge(method, fnPtr);
764 ALOGV("JNI-registered %s.%s:%s", clazz->descriptor, methodName, signature);
768 static const char* builtInPrefixes[] = {
771 "Lcom/google/android/",
776 "Lorg/apache/harmony/",
779 static bool shouldTrace(Method* method) {
780 const char* className = method->clazz->descriptor;
781 // Return true if the -Xjnitrace setting implies we should trace 'method'.
782 if (gDvm.jniTrace && strstr(className, gDvm.jniTrace)) {
785 // Return true if we're trying to log all third-party JNI activity and 'method' doesn't look
786 // like part of Android.
787 if (gDvmJni.logThirdPartyJni) {
788 for (size_t i = 0; i < NELEM(builtInPrefixes); ++i) {
789 if (strstr(className, builtInPrefixes[i]) == className) {
799 * Point "method->nativeFunc" at the JNI bridge, and overload "method->insns"
800 * to point at the actual function.
802 void dvmUseJNIBridge(Method* method, void* func) {
803 method->shouldTrace = shouldTrace(method);
805 // Does the method take any reference arguments?
806 method->noRef = true;
807 const char* cp = method->shorty;
808 while (*++cp != '\0') { // Pre-increment to skip return type.
810 method->noRef = false;
815 DalvikBridgeFunc bridge = gDvmJni.useCheckJni ? dvmCheckCallJNIMethod : dvmCallJNIMethod;
816 dvmSetNativeFunc(method, bridge, (const u2*) func);
819 // TODO: rewrite this to share code with CheckJNI's tracing...
820 static void appendValue(char type, const JValue value, char* buf, size_t n, bool appendComma)
822 size_t len = strlen(buf);
823 if (len >= n - 32) { // 32 should be longer than anything we could append.
832 if (value.b >= 0 && value.b < 10) {
833 sprintf(p, "%d", value.b);
835 sprintf(p, "%#x (%d)", value.b, value.b);
839 if (value.c < 0x7f && value.c >= ' ') {
840 sprintf(p, "U+%x ('%c')", value.c, value.c);
842 sprintf(p, "U+%x", value.c);
846 sprintf(p, "%g", value.d);
849 sprintf(p, "%g", value.f);
852 sprintf(p, "%d", value.i);
855 sprintf(p, "%#x", value.i);
858 sprintf(p, "%lld", value.j);
861 sprintf(p, "%d", value.s);
867 strcpy(p, value.z ? "true" : "false");
870 sprintf(p, "unknown type '%c'", type);
879 static void logNativeMethodEntry(const Method* method, const u4* args)
881 char thisString[32] = { 0 };
883 if (!dvmIsStaticMethod(method)) {
884 sprintf(thisString, "this=0x%08x ", *sp++);
887 char argsString[128]= { 0 };
888 const char* desc = &method->shorty[1];
889 while (*desc != '\0') {
890 char argType = *desc++;
892 if (argType == 'D' || argType == 'J') {
893 value.j = dvmGetArgLong(sp, 0);
898 appendValue(argType, value, argsString, sizeof(argsString),
902 std::string className(dvmHumanReadableDescriptor(method->clazz->descriptor));
903 char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
904 LOGI("-> %s %s%s %s(%s)", className.c_str(), method->name, signature, thisString, argsString);
908 static void logNativeMethodExit(const Method* method, Thread* self, const JValue returnValue)
910 std::string className(dvmHumanReadableDescriptor(method->clazz->descriptor));
911 char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
912 if (dvmCheckException(self)) {
913 Object* exception = dvmGetException(self);
914 std::string exceptionClassName(dvmHumanReadableDescriptor(exception->clazz->descriptor));
915 LOGI("<- %s %s%s threw %s", className.c_str(),
916 method->name, signature, exceptionClassName.c_str());
918 char returnValueString[128] = { 0 };
919 char returnType = method->shorty[0];
920 appendValue(returnType, returnValue, returnValueString, sizeof(returnValueString), false);
921 LOGI("<- %s %s%s returned %s", className.c_str(),
922 method->name, signature, returnValueString);
928 * Get the method currently being executed by examining the interp stack.
930 const Method* dvmGetCurrentJNIMethod() {
931 assert(dvmThreadSelf() != NULL);
933 void* fp = dvmThreadSelf()->interpSave.curFrame;
934 const Method* meth = SAVEAREA_FROM_FP(fp)->method;
936 assert(meth != NULL);
937 assert(dvmIsNativeMethod(meth));
942 * Track a JNI MonitorEnter in the current thread.
944 * The goal is to be able to "implicitly" release all JNI-held monitors
945 * when the thread detaches.
947 * Monitors may be entered multiple times, so we add a new entry for each
948 * enter call. It would be more efficient to keep a counter. At present
949 * there's no real motivation to improve this however.
951 static void trackMonitorEnter(Thread* self, Object* obj) {
952 static const int kInitialSize = 16;
953 ReferenceTable* refTable = &self->jniMonitorRefTable;
955 /* init table on first use */
956 if (refTable->table == NULL) {
957 assert(refTable->maxEntries == 0);
959 if (!dvmInitReferenceTable(refTable, kInitialSize, INT_MAX)) {
960 LOGE("Unable to initialize monitor tracking table");
965 if (!dvmAddToReferenceTable(refTable, obj)) {
966 /* ran out of memory? could throw exception instead */
967 LOGE("Unable to add entry to monitor tracking table");
970 LOGVV("--- added monitor %p", obj);
975 * Track a JNI MonitorExit in the current thread.
977 static void trackMonitorExit(Thread* self, Object* obj) {
978 ReferenceTable* pRefTable = &self->jniMonitorRefTable;
980 if (!dvmRemoveFromReferenceTable(pRefTable, pRefTable->table, obj)) {
981 LOGE("JNI monitor %p not found in tracking list", obj);
984 LOGVV("--- removed monitor %p", obj);
989 * Release all monitors held by the jniMonitorRefTable list.
991 void dvmReleaseJniMonitors(Thread* self) {
992 ReferenceTable* pRefTable = &self->jniMonitorRefTable;
993 Object** top = pRefTable->table;
998 Object** ptr = pRefTable->nextEntry;
999 while (--ptr >= top) {
1000 if (!dvmUnlockObject(self, *ptr)) {
1001 LOGW("Unable to unlock monitor %p at thread detach", *ptr);
1003 LOGVV("--- detach-releasing monitor %p", *ptr);
1008 pRefTable->nextEntry = pRefTable->table;
1012 * Determine if the specified class can be instantiated from JNI. This
1013 * is used by AllocObject / NewObject, which are documented as throwing
1014 * an exception for abstract and interface classes, and not accepting
1015 * array classes. We also want to reject attempts to create new Class
1016 * objects, since only DefineClass should do that.
1018 static bool canAllocClass(ClassObject* clazz) {
1019 if (dvmIsAbstractClass(clazz) || dvmIsInterfaceClass(clazz)) {
1020 /* JNI spec defines what this throws */
1021 dvmThrowInstantiationException(clazz, "abstract class or interface");
1023 } else if (dvmIsArrayClass(clazz) || dvmIsTheClassClass(clazz)) {
1024 /* spec says "must not" for arrays, ignores Class */
1025 dvmThrowInstantiationException(clazz, "wrong JNI function");
1033 * ===========================================================================
1035 * ===========================================================================
1039 * The functions here form a bridge between interpreted code and JNI native
1040 * functions. The basic task is to convert an array of primitives and
1041 * references into C-style function arguments. This is architecture-specific
1042 * and usually requires help from assembly code.
1044 * The bridge takes four arguments: the array of parameters, a place to
1045 * store the function result (if any), the method to call, and a pointer
1046 * to the current thread.
1048 * These functions aren't called directly from elsewhere in the VM.
1049 * A pointer in the Method struct points to one of these, and when a native
1050 * method is invoked the interpreter jumps to it.
1052 * (The "internal native" methods are invoked the same way, but instead
1053 * of calling through a bridge, the target method is called directly.)
1055 * The "args" array should not be modified, but we do so anyway for
1056 * performance reasons. We know that it points to the "outs" area on
1057 * the current method's interpreted stack. This area is ignored by the
1058 * precise GC, because there is no register map for a native method (for
1059 * an interpreted method the args would be listed in the argument set).
1060 * We know all of the values exist elsewhere on the interpreted stack,
1061 * because the method call setup copies them right before making the call,
1062 * so we don't have to worry about concealing stuff from the GC.
1064 * If we don't want to modify "args", we either have to create a local
1065 * copy and modify it before calling dvmPlatformInvoke, or we have to do
1066 * the local reference replacement within dvmPlatformInvoke. The latter
1067 * has some performance advantages, though if we can inline the local
1068 * reference adds we may win when there's a lot of reference args (unless
1069 * we want to code up some local ref table manipulation in assembly.
1073 * If necessary, convert the value in pResult from a local/global reference
1074 * to an object pointer.
1076 * If the returned reference is invalid, kInvalidIndirectRefObject will
1077 * be returned in pResult.
1079 static inline void convertReferenceResult(JNIEnv* env, JValue* pResult,
1080 const Method* method, Thread* self)
1082 if (method->shorty[0] == 'L' && !dvmCheckException(self) && pResult->l != NULL) {
1083 pResult->l = dvmDecodeIndirectRef(self, (jobject) pResult->l);
1088 * General form, handles all cases.
1090 void dvmCallJNIMethod(const u4* args, JValue* pResult, const Method* method, Thread* self) {
1091 u4* modArgs = (u4*) args;
1092 jclass staticMethodClass = NULL;
1094 u4 accessFlags = method->accessFlags;
1095 bool isSynchronized = (accessFlags & ACC_SYNCHRONIZED) != 0;
1097 //LOGI("JNI calling %p (%s.%s:%s):", method->insns,
1098 // method->clazz->descriptor, method->name, method->shorty);
1101 * Walk the argument list, creating local references for appropriate
1106 if ((accessFlags & ACC_STATIC) != 0) {
1107 lockObj = (Object*) method->clazz;
1108 /* add the class object we pass in */
1109 staticMethodClass = (jclass) addLocalReference(self, (Object*) method->clazz);
1111 lockObj = (Object*) args[0];
1113 modArgs[idx++] = (u4) addLocalReference(self, (Object*) modArgs[0]);
1116 if (!method->noRef) {
1117 const char* shorty = &method->shorty[1]; /* skip return type */
1118 while (*shorty != '\0') {
1119 switch (*shorty++) {
1121 //LOGI(" local %d: 0x%08x", idx, modArgs[idx]);
1122 if (modArgs[idx] != 0) {
1123 modArgs[idx] = (u4) addLocalReference(self, (Object*) modArgs[idx]);
1131 /* Z B C S I -- do nothing */
1138 if (UNLIKELY(method->shouldTrace)) {
1139 logNativeMethodEntry(method, args);
1141 if (UNLIKELY(isSynchronized)) {
1142 dvmLockObject(self, lockObj);
1145 ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
1147 ANDROID_MEMBAR_FULL(); /* guarantee ordering on method->insns */
1148 assert(method->insns != NULL);
1150 JNIEnv* env = self->jniEnv;
1151 COMPUTE_STACK_SUM(self);
1152 dvmPlatformInvoke(env,
1153 (ClassObject*) staticMethodClass,
1154 method->jniArgInfo, method->insSize, modArgs, method->shorty,
1155 (void*) method->insns, pResult);
1156 CHECK_STACK_SUM(self);
1158 dvmChangeStatus(self, oldStatus);
1160 convertReferenceResult(env, pResult, method, self);
1162 if (UNLIKELY(isSynchronized)) {
1163 dvmUnlockObject(self, lockObj);
1165 if (UNLIKELY(method->shouldTrace)) {
1166 logNativeMethodExit(method, self, *pResult);
1171 * ===========================================================================
1172 * JNI implementation
1173 * ===========================================================================
1177 * Return the version of the native method interface.
1179 static jint GetVersion(JNIEnv* env) {
1181 * There is absolutely no need to toggle the mode for correct behavior.
1182 * However, it does provide native code with a simple "suspend self
1183 * if necessary" call.
1185 ScopedJniThreadState ts(env);
1186 return JNI_VERSION_1_6;
1190 * Create a new class from a bag of bytes.
1192 * This is not currently supported within Dalvik.
1194 static jclass DefineClass(JNIEnv* env, const char *name, jobject loader,
1195 const jbyte* buf, jsize bufLen)
1197 UNUSED_PARAMETER(name);
1198 UNUSED_PARAMETER(loader);
1199 UNUSED_PARAMETER(buf);
1200 UNUSED_PARAMETER(bufLen);
1202 ScopedJniThreadState ts(env);
1203 LOGW("JNI DefineClass is not supported");
1208 * Find a class by name.
1210 * We have to use the "no init" version of FindClass here, because we might
1211 * be getting the class prior to registering native methods that will be
1214 * We need to get the class loader associated with the current native
1215 * method. If there is no native method, e.g. we're calling this from native
1216 * code right after creating the VM, the spec says we need to use the class
1217 * loader returned by "ClassLoader.getBaseClassLoader". There is no such
1218 * method, but it's likely they meant ClassLoader.getSystemClassLoader.
1219 * We can't get that until after the VM has initialized though.
1221 static jclass FindClass(JNIEnv* env, const char* name) {
1222 ScopedJniThreadState ts(env);
1224 const Method* thisMethod = dvmGetCurrentJNIMethod();
1225 assert(thisMethod != NULL);
1228 Object* trackedLoader = NULL;
1229 if (ts.self()->classLoaderOverride != NULL) {
1230 /* hack for JNI_OnLoad */
1231 assert(strcmp(thisMethod->name, "nativeLoad") == 0);
1232 loader = ts.self()->classLoaderOverride;
1233 } else if (thisMethod == gDvm.methDalvikSystemNativeStart_main ||
1234 thisMethod == gDvm.methDalvikSystemNativeStart_run) {
1235 /* start point of invocation interface */
1236 if (!gDvm.initializing) {
1237 loader = trackedLoader = dvmGetSystemClassLoader();
1242 loader = thisMethod->clazz->classLoader;
1245 char* descriptor = dvmNameToDescriptor(name);
1246 if (descriptor == NULL) {
1249 ClassObject* clazz = dvmFindClassNoInit(descriptor, loader);
1252 jclass jclazz = (jclass) addLocalReference(ts.self(), (Object*) clazz);
1253 dvmReleaseTrackedAlloc(trackedLoader, ts.self());
1258 * Return the superclass of a class.
1260 static jclass GetSuperclass(JNIEnv* env, jclass jclazz) {
1261 ScopedJniThreadState ts(env);
1262 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1263 return (jclass) addLocalReference(ts.self(), (Object*)clazz->super);
1267 * Determine whether an object of clazz1 can be safely cast to clazz2.
1269 * Like IsInstanceOf, but with a pair of class objects instead of obj+class.
1271 static jboolean IsAssignableFrom(JNIEnv* env, jclass jclazz1, jclass jclazz2) {
1272 ScopedJniThreadState ts(env);
1273 ClassObject* clazz1 = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz1);
1274 ClassObject* clazz2 = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz2);
1275 return dvmInstanceof(clazz1, clazz2);
1279 * Given a java.lang.reflect.Method or .Constructor, return a methodID.
1281 static jmethodID FromReflectedMethod(JNIEnv* env, jobject jmethod) {
1282 ScopedJniThreadState ts(env);
1283 Object* method = dvmDecodeIndirectRef(ts.self(), jmethod);
1284 return (jmethodID) dvmGetMethodFromReflectObj(method);
1288 * Given a java.lang.reflect.Field, return a fieldID.
1290 static jfieldID FromReflectedField(JNIEnv* env, jobject jfield) {
1291 ScopedJniThreadState ts(env);
1292 Object* field = dvmDecodeIndirectRef(ts.self(), jfield);
1293 return (jfieldID) dvmGetFieldFromReflectObj(field);
1297 * Convert a methodID to a java.lang.reflect.Method or .Constructor.
1299 * (The "isStatic" field does not appear in the spec.)
1301 * Throws OutOfMemory and returns NULL on failure.
1303 static jobject ToReflectedMethod(JNIEnv* env, jclass jcls, jmethodID methodID, jboolean isStatic) {
1304 ScopedJniThreadState ts(env);
1305 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jcls);
1306 Object* obj = dvmCreateReflectObjForMethod(clazz, (Method*) methodID);
1307 dvmReleaseTrackedAlloc(obj, NULL);
1308 return addLocalReference(ts.self(), obj);
1312 * Convert a fieldID to a java.lang.reflect.Field.
1314 * (The "isStatic" field does not appear in the spec.)
1316 * Throws OutOfMemory and returns NULL on failure.
1318 static jobject ToReflectedField(JNIEnv* env, jclass jcls, jfieldID fieldID, jboolean isStatic) {
1319 ScopedJniThreadState ts(env);
1320 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jcls);
1321 Object* obj = dvmCreateReflectObjForField(clazz, (Field*) fieldID);
1322 dvmReleaseTrackedAlloc(obj, NULL);
1323 return addLocalReference(ts.self(), obj);
1327 * Take this exception and throw it.
1329 static jint Throw(JNIEnv* env, jthrowable jobj) {
1330 ScopedJniThreadState ts(env);
1332 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1333 dvmSetException(ts.self(), obj);
1340 * Constructs an exception object from the specified class with the message
1341 * specified by "message", and throws it.
1343 static jint ThrowNew(JNIEnv* env, jclass jclazz, const char* message) {
1344 ScopedJniThreadState ts(env);
1345 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1346 dvmThrowException(clazz, message);
1347 // TODO: should return failure if this didn't work (e.g. OOM)
1352 * If an exception is being thrown, return the exception object. Otherwise,
1355 * TODO: if there is no pending exception, we should be able to skip the
1356 * enter/exit checks. If we find one, we need to enter and then re-fetch
1357 * the exception (in case it got moved by a compacting GC).
1359 static jthrowable ExceptionOccurred(JNIEnv* env) {
1360 ScopedJniThreadState ts(env);
1361 Object* exception = dvmGetException(ts.self());
1362 jthrowable localException = (jthrowable) addLocalReference(ts.self(), exception);
1363 if (localException == NULL && exception != NULL) {
1365 * We were unable to add a new local reference, and threw a new
1366 * exception. We can't return "exception", because it's not a
1367 * local reference. So we have to return NULL, indicating that
1368 * there was no exception, even though it's pretty much raining
1369 * exceptions in here.
1371 LOGW("JNI WARNING: addLocal/exception combo");
1373 return localException;
1377 * Print an exception and stack trace to stderr.
1379 static void ExceptionDescribe(JNIEnv* env) {
1380 ScopedJniThreadState ts(env);
1381 Object* exception = dvmGetException(ts.self());
1382 if (exception != NULL) {
1383 dvmPrintExceptionStackTrace();
1385 LOGI("Odd: ExceptionDescribe called, but no exception pending");
1390 * Clear the exception currently being thrown.
1392 * TODO: we should be able to skip the enter/exit stuff.
1394 static void ExceptionClear(JNIEnv* env) {
1395 ScopedJniThreadState ts(env);
1396 dvmClearException(ts.self());
1400 * Kill the VM. This function does not return.
1402 static void FatalError(JNIEnv* env, const char* msg) {
1403 //dvmChangeStatus(NULL, THREAD_RUNNING);
1404 LOGE("JNI posting fatal error: %s", msg);
1409 * Push a new JNI frame on the stack, with a new set of locals.
1411 * The new frame must have the same method pointer. (If for no other
1412 * reason than FindClass needs it to get the appropriate class loader.)
1414 static jint PushLocalFrame(JNIEnv* env, jint capacity) {
1415 ScopedJniThreadState ts(env);
1416 if (!ensureLocalCapacity(ts.self(), capacity) ||
1417 !dvmPushLocalFrame(ts.self(), dvmGetCurrentJNIMethod()))
1419 /* yes, OutOfMemoryError, not StackOverflowError */
1420 dvmClearException(ts.self());
1421 dvmThrowOutOfMemoryError("out of stack in JNI PushLocalFrame");
1428 * Pop the local frame off. If "jresult" is not null, add it as a
1429 * local reference on the now-current frame.
1431 static jobject PopLocalFrame(JNIEnv* env, jobject jresult) {
1432 ScopedJniThreadState ts(env);
1433 Object* result = dvmDecodeIndirectRef(ts.self(), jresult);
1434 if (!dvmPopLocalFrame(ts.self())) {
1435 LOGW("JNI WARNING: too many PopLocalFrame calls");
1436 dvmClearException(ts.self());
1437 dvmThrowRuntimeException("too many PopLocalFrame calls");
1439 return addLocalReference(ts.self(), result);
1443 * Add a reference to the global list.
1445 static jobject NewGlobalRef(JNIEnv* env, jobject jobj) {
1446 ScopedJniThreadState ts(env);
1447 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1448 return addGlobalReference(obj);
1452 * Delete a reference from the global list.
1454 static void DeleteGlobalRef(JNIEnv* env, jobject jglobalRef) {
1455 ScopedJniThreadState ts(env);
1456 deleteGlobalReference(jglobalRef);
1461 * Add a reference to the local list.
1463 static jobject NewLocalRef(JNIEnv* env, jobject jobj) {
1464 ScopedJniThreadState ts(env);
1465 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1466 return addLocalReference(ts.self(), obj);
1470 * Delete a reference from the local list.
1472 static void DeleteLocalRef(JNIEnv* env, jobject jlocalRef) {
1473 ScopedJniThreadState ts(env);
1474 deleteLocalReference(ts.self(), jlocalRef);
1478 * Ensure that the local references table can hold at least this many
1481 static jint EnsureLocalCapacity(JNIEnv* env, jint capacity) {
1482 ScopedJniThreadState ts(env);
1483 bool okay = ensureLocalCapacity(ts.self(), capacity);
1485 dvmThrowOutOfMemoryError("can't ensure local reference capacity");
1487 return okay ? 0 : -1;
1492 * Determine whether two Object references refer to the same underlying object.
1494 static jboolean IsSameObject(JNIEnv* env, jobject jref1, jobject jref2) {
1495 ScopedJniThreadState ts(env);
1496 Object* obj1 = dvmDecodeIndirectRef(ts.self(), jref1);
1497 Object* obj2 = dvmDecodeIndirectRef(ts.self(), jref2);
1498 return (obj1 == obj2);
1502 * Allocate a new object without invoking any constructors.
1504 static jobject AllocObject(JNIEnv* env, jclass jclazz) {
1505 ScopedJniThreadState ts(env);
1507 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1508 if (!canAllocClass(clazz) ||
1509 (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)))
1511 assert(dvmCheckException(ts.self()));
1515 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1516 return addLocalReference(ts.self(), newObj);
1520 * Allocate a new object and invoke the supplied constructor.
1522 static jobject NewObject(JNIEnv* env, jclass jclazz, jmethodID methodID, ...) {
1523 ScopedJniThreadState ts(env);
1524 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1526 if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
1527 assert(dvmCheckException(ts.self()));
1531 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1532 jobject result = addLocalReference(ts.self(), newObj);
1533 if (newObj != NULL) {
1536 va_start(args, methodID);
1537 dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args);
1543 static jobject NewObjectV(JNIEnv* env, jclass jclazz, jmethodID methodID, va_list args) {
1544 ScopedJniThreadState ts(env);
1545 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1547 if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
1548 assert(dvmCheckException(ts.self()));
1552 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1553 jobject result = addLocalReference(ts.self(), newObj);
1554 if (newObj != NULL) {
1556 dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args);
1561 static jobject NewObjectA(JNIEnv* env, jclass jclazz, jmethodID methodID, jvalue* args) {
1562 ScopedJniThreadState ts(env);
1563 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1565 if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
1566 assert(dvmCheckException(ts.self()));
1570 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1571 jobject result = addLocalReference(ts.self(), newObj);
1572 if (newObj != NULL) {
1574 dvmCallMethodA(ts.self(), (Method*) methodID, newObj, true, &unused, args);
1580 * Returns the class of an object.
1582 * JNI spec says: obj must not be NULL.
1584 static jclass GetObjectClass(JNIEnv* env, jobject jobj) {
1585 ScopedJniThreadState ts(env);
1587 assert(jobj != NULL);
1589 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1590 return (jclass) addLocalReference(ts.self(), (Object*) obj->clazz);
1594 * Determine whether "obj" is an instance of "clazz".
1596 static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass jclazz) {
1597 ScopedJniThreadState ts(env);
1599 assert(jclazz != NULL);
1604 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1605 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1606 return dvmInstanceof(obj->clazz, clazz);
1610 * Get a method ID for an instance method.
1612 * While Dalvik bytecode has distinct instructions for virtual, super,
1613 * static, direct, and interface method invocation, JNI only provides
1614 * two functions for acquiring a method ID. This call handles everything
1615 * but static methods.
1617 * JNI defines <init> as an instance method, but Dalvik considers it a
1618 * "direct" method, so we have to special-case it here.
1620 * Dalvik also puts all private methods into the "direct" list, so we
1621 * really need to just search both lists.
1623 static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1624 ScopedJniThreadState ts(env);
1626 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1627 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1628 assert(dvmCheckException(ts.self()));
1629 } else if (dvmIsInterfaceClass(clazz)) {
1630 Method* meth = dvmFindInterfaceMethodHierByDescriptor(clazz, name, sig);
1632 dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
1633 "no method with name='%s' signature='%s' in interface %s",
1634 name, sig, clazz->descriptor);
1636 return (jmethodID) meth;
1638 Method* meth = dvmFindVirtualMethodHierByDescriptor(clazz, name, sig);
1640 /* search private methods and constructors; non-hierarchical */
1641 meth = dvmFindDirectMethodByDescriptor(clazz, name, sig);
1643 if (meth != NULL && dvmIsStaticMethod(meth)) {
1645 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
1646 LOGD("GetMethodID: not returning static method %s.%s %s",
1647 clazz->descriptor, meth->name, desc);
1653 dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
1654 "no method with name='%s' signature='%s' in class %s",
1655 name, sig, clazz->descriptor);
1658 * The method's class may not be the same as clazz, but if
1659 * it isn't this must be a virtual method and the class must
1660 * be a superclass (and, hence, already initialized).
1662 assert(dvmIsClassInitialized(meth->clazz) || dvmIsClassInitializing(meth->clazz));
1664 return (jmethodID) meth;
1668 * Get a field ID (instance fields).
1670 static jfieldID GetFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1671 ScopedJniThreadState ts(env);
1673 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1675 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1676 assert(dvmCheckException(ts.self()));
1680 jfieldID id = (jfieldID) dvmFindInstanceFieldHier(clazz, name, sig);
1682 dvmThrowExceptionFmt(gDvm.exNoSuchFieldError,
1683 "no field with name='%s' signature='%s' in class %s",
1684 name, sig, clazz->descriptor);
1690 * Get the method ID for a static method in a class.
1692 static jmethodID GetStaticMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1693 ScopedJniThreadState ts(env);
1695 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1696 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1697 assert(dvmCheckException(ts.self()));
1701 Method* meth = dvmFindDirectMethodHierByDescriptor(clazz, name, sig);
1703 /* make sure it's static, not virtual+private */
1704 if (meth != NULL && !dvmIsStaticMethod(meth)) {
1706 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
1707 LOGD("GetStaticMethodID: not returning nonstatic method %s.%s %s",
1708 clazz->descriptor, meth->name, desc);
1714 jmethodID id = (jmethodID) meth;
1716 dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
1717 "no static method with name='%s' signature='%s' in class %s",
1718 name, sig, clazz->descriptor);
1724 * Get a field ID (static fields).
1726 static jfieldID GetStaticFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1727 ScopedJniThreadState ts(env);
1729 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1730 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1731 assert(dvmCheckException(ts.self()));
1735 jfieldID id = (jfieldID) dvmFindStaticFieldHier(clazz, name, sig);
1737 dvmThrowExceptionFmt(gDvm.exNoSuchFieldError,
1738 "no static field with name='%s' signature='%s' in class %s",
1739 name, sig, clazz->descriptor);
1745 * Get a static field.
1747 * If we get an object reference, add it to the local refs list.
1749 #define GET_STATIC_TYPE_FIELD(_ctype, _jname, _isref) \
1750 static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass jclazz, \
1753 UNUSED_PARAMETER(jclazz); \
1754 ScopedJniThreadState ts(env); \
1755 StaticField* sfield = (StaticField*) fieldID; \
1757 if (dvmIsVolatileField(sfield)) { \
1758 if (_isref) { /* only when _ctype==jobject */ \
1759 Object* obj = dvmGetStaticFieldObjectVolatile(sfield); \
1760 value = (_ctype)(u4)addLocalReference(ts.self(), obj); \
1762 value = (_ctype) dvmGetStaticField##_jname##Volatile(sfield);\
1766 Object* obj = dvmGetStaticFieldObject(sfield); \
1767 value = (_ctype)(u4)addLocalReference(ts.self(), obj); \
1769 value = (_ctype) dvmGetStaticField##_jname(sfield); \
1774 GET_STATIC_TYPE_FIELD(jobject, Object, true);
1775 GET_STATIC_TYPE_FIELD(jboolean, Boolean, false);
1776 GET_STATIC_TYPE_FIELD(jbyte, Byte, false);
1777 GET_STATIC_TYPE_FIELD(jchar, Char, false);
1778 GET_STATIC_TYPE_FIELD(jshort, Short, false);
1779 GET_STATIC_TYPE_FIELD(jint, Int, false);
1780 GET_STATIC_TYPE_FIELD(jlong, Long, false);
1781 GET_STATIC_TYPE_FIELD(jfloat, Float, false);
1782 GET_STATIC_TYPE_FIELD(jdouble, Double, false);
1785 * Set a static field.
1787 #define SET_STATIC_TYPE_FIELD(_ctype, _ctype2, _jname, _isref) \
1788 static void SetStatic##_jname##Field(JNIEnv* env, jclass jclazz, \
1789 jfieldID fieldID, _ctype value) \
1791 UNUSED_PARAMETER(jclazz); \
1792 ScopedJniThreadState ts(env); \
1793 StaticField* sfield = (StaticField*) fieldID; \
1794 if (dvmIsVolatileField(sfield)) { \
1795 if (_isref) { /* only when _ctype==jobject */ \
1796 Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1797 dvmSetStaticFieldObjectVolatile(sfield, valObj); \
1799 dvmSetStaticField##_jname##Volatile(sfield, (_ctype2)value);\
1803 Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1804 dvmSetStaticFieldObject(sfield, valObj); \
1806 dvmSetStaticField##_jname(sfield, (_ctype2)value); \
1810 SET_STATIC_TYPE_FIELD(jobject, Object*, Object, true);
1811 SET_STATIC_TYPE_FIELD(jboolean, bool, Boolean, false);
1812 SET_STATIC_TYPE_FIELD(jbyte, s1, Byte, false);
1813 SET_STATIC_TYPE_FIELD(jchar, u2, Char, false);
1814 SET_STATIC_TYPE_FIELD(jshort, s2, Short, false);
1815 SET_STATIC_TYPE_FIELD(jint, s4, Int, false);
1816 SET_STATIC_TYPE_FIELD(jlong, s8, Long, false);
1817 SET_STATIC_TYPE_FIELD(jfloat, float, Float, false);
1818 SET_STATIC_TYPE_FIELD(jdouble, double, Double, false);
1821 * Get an instance field.
1823 * If we get an object reference, add it to the local refs list.
1825 #define GET_TYPE_FIELD(_ctype, _jname, _isref) \
1826 static _ctype Get##_jname##Field(JNIEnv* env, jobject jobj, \
1829 ScopedJniThreadState ts(env); \
1830 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1831 InstField* field = (InstField*) fieldID; \
1833 if (dvmIsVolatileField(field)) { \
1834 if (_isref) { /* only when _ctype==jobject */ \
1836 dvmGetFieldObjectVolatile(obj, field->byteOffset); \
1837 value = (_ctype)(u4)addLocalReference(ts.self(), valObj); \
1840 dvmGetField##_jname##Volatile(obj, field->byteOffset); \
1844 Object* valObj = dvmGetFieldObject(obj, field->byteOffset); \
1845 value = (_ctype)(u4)addLocalReference(ts.self(), valObj); \
1847 value = (_ctype) dvmGetField##_jname(obj, field->byteOffset);\
1852 GET_TYPE_FIELD(jobject, Object, true);
1853 GET_TYPE_FIELD(jboolean, Boolean, false);
1854 GET_TYPE_FIELD(jbyte, Byte, false);
1855 GET_TYPE_FIELD(jchar, Char, false);
1856 GET_TYPE_FIELD(jshort, Short, false);
1857 GET_TYPE_FIELD(jint, Int, false);
1858 GET_TYPE_FIELD(jlong, Long, false);
1859 GET_TYPE_FIELD(jfloat, Float, false);
1860 GET_TYPE_FIELD(jdouble, Double, false);
1863 * Set an instance field.
1865 #define SET_TYPE_FIELD(_ctype, _ctype2, _jname, _isref) \
1866 static void Set##_jname##Field(JNIEnv* env, jobject jobj, \
1867 jfieldID fieldID, _ctype value) \
1869 ScopedJniThreadState ts(env); \
1870 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1871 InstField* field = (InstField*) fieldID; \
1872 if (dvmIsVolatileField(field)) { \
1873 if (_isref) { /* only when _ctype==jobject */ \
1874 Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1875 dvmSetFieldObjectVolatile(obj, field->byteOffset, valObj); \
1877 dvmSetField##_jname##Volatile(obj, \
1878 field->byteOffset, (_ctype2)value); \
1882 Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1883 dvmSetFieldObject(obj, field->byteOffset, valObj); \
1885 dvmSetField##_jname(obj, \
1886 field->byteOffset, (_ctype2)value); \
1890 SET_TYPE_FIELD(jobject, Object*, Object, true);
1891 SET_TYPE_FIELD(jboolean, bool, Boolean, false);
1892 SET_TYPE_FIELD(jbyte, s1, Byte, false);
1893 SET_TYPE_FIELD(jchar, u2, Char, false);
1894 SET_TYPE_FIELD(jshort, s2, Short, false);
1895 SET_TYPE_FIELD(jint, s4, Int, false);
1896 SET_TYPE_FIELD(jlong, s8, Long, false);
1897 SET_TYPE_FIELD(jfloat, float, Float, false);
1898 SET_TYPE_FIELD(jdouble, double, Double, false);
1901 * Make a virtual method call.
1903 * Three versions (..., va_list, jvalue[]) for each return type. If we're
1904 * returning an Object, we have to add it to the local references table.
1906 #define CALL_VIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \
1907 static _ctype Call##_jname##Method(JNIEnv* env, jobject jobj, \
1908 jmethodID methodID, ...) \
1910 ScopedJniThreadState ts(env); \
1911 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1912 const Method* meth; \
1915 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
1916 if (meth == NULL) { \
1919 va_start(args, methodID); \
1920 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \
1922 if (_isref && !dvmCheckException(ts.self())) \
1923 result.l = (Object*)addLocalReference(ts.self(), result.l); \
1926 static _ctype Call##_jname##MethodV(JNIEnv* env, jobject jobj, \
1927 jmethodID methodID, va_list args) \
1929 ScopedJniThreadState ts(env); \
1930 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1931 const Method* meth; \
1933 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
1934 if (meth == NULL) { \
1937 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \
1938 if (_isref && !dvmCheckException(ts.self())) \
1939 result.l = (Object*)addLocalReference(ts.self(), result.l); \
1942 static _ctype Call##_jname##MethodA(JNIEnv* env, jobject jobj, \
1943 jmethodID methodID, jvalue* args) \
1945 ScopedJniThreadState ts(env); \
1946 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1947 const Method* meth; \
1949 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
1950 if (meth == NULL) { \
1953 dvmCallMethodA(ts.self(), meth, obj, true, &result, args); \
1954 if (_isref && !dvmCheckException(ts.self())) \
1955 result.l = (Object*)addLocalReference(ts.self(), result.l); \
1958 CALL_VIRTUAL(jobject, Object, NULL, (jobject) result.l, true);
1959 CALL_VIRTUAL(jboolean, Boolean, 0, result.z, false);
1960 CALL_VIRTUAL(jbyte, Byte, 0, result.b, false);
1961 CALL_VIRTUAL(jchar, Char, 0, result.c, false);
1962 CALL_VIRTUAL(jshort, Short, 0, result.s, false);
1963 CALL_VIRTUAL(jint, Int, 0, result.i, false);
1964 CALL_VIRTUAL(jlong, Long, 0, result.j, false);
1965 CALL_VIRTUAL(jfloat, Float, 0.0f, result.f, false);
1966 CALL_VIRTUAL(jdouble, Double, 0.0, result.d, false);
1967 CALL_VIRTUAL(void, Void, , , false);
1970 * Make a "non-virtual" method call. We're still calling a virtual method,
1971 * but this time we're not doing an indirection through the object's vtable.
1972 * The "clazz" parameter defines which implementation of a method we want.
1974 * Three versions (..., va_list, jvalue[]) for each return type.
1976 #define CALL_NONVIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \
1977 static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, jobject jobj, \
1978 jclass jclazz, jmethodID methodID, ...) \
1980 ScopedJniThreadState ts(env); \
1981 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1982 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz); \
1983 const Method* meth; \
1986 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
1987 if (meth == NULL) { \
1990 va_start(args, methodID); \
1991 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \
1992 if (_isref && !dvmCheckException(ts.self())) \
1993 result.l = (Object*)addLocalReference(ts.self(), result.l); \
1997 static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, jobject jobj,\
1998 jclass jclazz, jmethodID methodID, va_list args) \
2000 ScopedJniThreadState ts(env); \
2001 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
2002 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz); \
2003 const Method* meth; \
2005 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
2006 if (meth == NULL) { \
2009 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \
2010 if (_isref && !dvmCheckException(ts.self())) \
2011 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2014 static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, jobject jobj,\
2015 jclass jclazz, jmethodID methodID, jvalue* args) \
2017 ScopedJniThreadState ts(env); \
2018 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
2019 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz); \
2020 const Method* meth; \
2022 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
2023 if (meth == NULL) { \
2026 dvmCallMethodA(ts.self(), meth, obj, true, &result, args); \
2027 if (_isref && !dvmCheckException(ts.self())) \
2028 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2031 CALL_NONVIRTUAL(jobject, Object, NULL, (jobject) result.l, true);
2032 CALL_NONVIRTUAL(jboolean, Boolean, 0, result.z, false);
2033 CALL_NONVIRTUAL(jbyte, Byte, 0, result.b, false);
2034 CALL_NONVIRTUAL(jchar, Char, 0, result.c, false);
2035 CALL_NONVIRTUAL(jshort, Short, 0, result.s, false);
2036 CALL_NONVIRTUAL(jint, Int, 0, result.i, false);
2037 CALL_NONVIRTUAL(jlong, Long, 0, result.j, false);
2038 CALL_NONVIRTUAL(jfloat, Float, 0.0f, result.f, false);
2039 CALL_NONVIRTUAL(jdouble, Double, 0.0, result.d, false);
2040 CALL_NONVIRTUAL(void, Void, , , false);
2044 * Call a static method.
2046 #define CALL_STATIC(_ctype, _jname, _retfail, _retok, _isref) \
2047 static _ctype CallStatic##_jname##Method(JNIEnv* env, jclass jclazz, \
2048 jmethodID methodID, ...) \
2050 UNUSED_PARAMETER(jclazz); \
2051 ScopedJniThreadState ts(env); \
2054 va_start(args, methodID); \
2055 dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
2057 if (_isref && !dvmCheckException(ts.self())) \
2058 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2061 static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass jclazz, \
2062 jmethodID methodID, va_list args) \
2064 UNUSED_PARAMETER(jclazz); \
2065 ScopedJniThreadState ts(env); \
2067 dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
2068 if (_isref && !dvmCheckException(ts.self())) \
2069 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2072 static _ctype CallStatic##_jname##MethodA(JNIEnv* env, jclass jclazz, \
2073 jmethodID methodID, jvalue* args) \
2075 UNUSED_PARAMETER(jclazz); \
2076 ScopedJniThreadState ts(env); \
2078 dvmCallMethodA(ts.self(), (Method*)methodID, NULL, true, &result, args);\
2079 if (_isref && !dvmCheckException(ts.self())) \
2080 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2083 CALL_STATIC(jobject, Object, NULL, (jobject) result.l, true);
2084 CALL_STATIC(jboolean, Boolean, 0, result.z, false);
2085 CALL_STATIC(jbyte, Byte, 0, result.b, false);
2086 CALL_STATIC(jchar, Char, 0, result.c, false);
2087 CALL_STATIC(jshort, Short, 0, result.s, false);
2088 CALL_STATIC(jint, Int, 0, result.i, false);
2089 CALL_STATIC(jlong, Long, 0, result.j, false);
2090 CALL_STATIC(jfloat, Float, 0.0f, result.f, false);
2091 CALL_STATIC(jdouble, Double, 0.0, result.d, false);
2092 CALL_STATIC(void, Void, , , false);
2095 * Create a new String from Unicode data.
2097 * If "len" is zero, we will return an empty string even if "unicodeChars"
2098 * is NULL. (The JNI spec is vague here.)
2100 static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) {
2101 ScopedJniThreadState ts(env);
2102 StringObject* jstr = dvmCreateStringFromUnicode(unicodeChars, len);
2106 dvmReleaseTrackedAlloc((Object*) jstr, NULL);
2107 return (jstring) addLocalReference(ts.self(), (Object*) jstr);
2111 * Return the length of a String in Unicode character units.
2113 static jsize GetStringLength(JNIEnv* env, jstring jstr) {
2114 ScopedJniThreadState ts(env);
2115 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2116 return strObj->length();
2121 * Get a string's character data.
2123 * The result is guaranteed to be valid until ReleaseStringChars is
2124 * called, which means we have to pin it or return a copy.
2126 static const jchar* GetStringChars(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2127 ScopedJniThreadState ts(env);
2129 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2130 ArrayObject* strChars = strObj->array();
2132 pinPrimitiveArray(strChars);
2134 const u2* data = strObj->chars();
2135 if (isCopy != NULL) {
2136 *isCopy = JNI_FALSE;
2138 return (jchar*) data;
2142 * Release our grip on some characters from a string.
2144 static void ReleaseStringChars(JNIEnv* env, jstring jstr, const jchar* chars) {
2145 ScopedJniThreadState ts(env);
2146 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2147 ArrayObject* strChars = strObj->array();
2148 unpinPrimitiveArray(strChars);
2152 * Create a new java.lang.String object from chars in modified UTF-8 form.
2154 * The spec doesn't say how to handle a NULL string. Popular desktop VMs
2155 * accept it and return a NULL pointer in response.
2157 static jstring NewStringUTF(JNIEnv* env, const char* bytes) {
2158 ScopedJniThreadState ts(env);
2159 if (bytes == NULL) {
2162 /* note newStr could come back NULL on OOM */
2163 StringObject* newStr = dvmCreateStringFromCstr(bytes);
2164 jstring result = (jstring) addLocalReference(ts.self(), (Object*) newStr);
2165 dvmReleaseTrackedAlloc((Object*)newStr, NULL);
2170 * Return the length in bytes of the modified UTF-8 form of the string.
2172 static jsize GetStringUTFLength(JNIEnv* env, jstring jstr) {
2173 ScopedJniThreadState ts(env);
2174 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2175 if (strObj == NULL) {
2176 return 0; // Should we throw something or assert?
2178 return strObj->utfLength();
2182 * Convert "string" to modified UTF-8 and return a pointer. The returned
2183 * value must be released with ReleaseStringUTFChars.
2185 * According to the JNI reference, "Returns a pointer to a UTF-8 string,
2186 * or NULL if the operation fails. Returns NULL if and only if an invocation
2187 * of this function has thrown an exception."
2189 * The behavior here currently follows that of other open-source VMs, which
2190 * quietly return NULL if "string" is NULL. We should consider throwing an
2191 * NPE. (The CheckJNI code blows up if you try to pass in a NULL string,
2192 * which should catch this sort of thing during development.) Certain other
2193 * VMs will crash with a segmentation fault.
2195 static const char* GetStringUTFChars(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2196 ScopedJniThreadState ts(env);
2198 /* this shouldn't happen; throw NPE? */
2201 if (isCopy != NULL) {
2204 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2205 char* newStr = dvmCreateCstrFromString(strObj);
2206 if (newStr == NULL) {
2207 /* assume memory failure */
2208 dvmThrowOutOfMemoryError("native heap string alloc failed");
2214 * Release a string created by GetStringUTFChars().
2216 static void ReleaseStringUTFChars(JNIEnv* env, jstring jstr, const char* utf) {
2217 ScopedJniThreadState ts(env);
2222 * Return the capacity of the array.
2224 static jsize GetArrayLength(JNIEnv* env, jarray jarr) {
2225 ScopedJniThreadState ts(env);
2226 ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2227 return arrObj->length;
2231 * Construct a new array that holds objects from class "elementClass".
2233 static jobjectArray NewObjectArray(JNIEnv* env, jsize length,
2234 jclass jelementClass, jobject jinitialElement)
2236 ScopedJniThreadState ts(env);
2238 if (jelementClass == NULL) {
2239 dvmThrowNullPointerException("JNI NewObjectArray elementClass == NULL");
2243 ClassObject* elemClassObj = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jelementClass);
2244 ClassObject* arrayClass = dvmFindArrayClassForElement(elemClassObj);
2245 ArrayObject* newObj = dvmAllocArrayByClass(arrayClass, length, ALLOC_DEFAULT);
2246 if (newObj == NULL) {
2247 assert(dvmCheckException(ts.self()));
2250 jobjectArray newArray = (jobjectArray) addLocalReference(ts.self(), (Object*) newObj);
2251 dvmReleaseTrackedAlloc((Object*) newObj, NULL);
2254 * Initialize the array.
2256 if (jinitialElement != NULL) {
2257 Object* initialElement = dvmDecodeIndirectRef(ts.self(), jinitialElement);
2258 Object** arrayData = (Object**) (void*) newObj->contents;
2259 for (jsize i = 0; i < length; ++i) {
2260 arrayData[i] = initialElement;
2267 static bool checkArrayElementBounds(ArrayObject* arrayObj, jsize index) {
2268 assert(arrayObj != NULL);
2269 if (index < 0 || index >= (int) arrayObj->length) {
2270 dvmThrowArrayIndexOutOfBoundsException(arrayObj->length, index);
2277 * Get one element of an Object array.
2279 * Add the object to the local references table in case the array goes away.
2281 static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index) {
2282 ScopedJniThreadState ts(env);
2284 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2285 if (!checkArrayElementBounds(arrayObj, index)) {
2289 Object* value = ((Object**) (void*) arrayObj->contents)[index];
2290 return addLocalReference(ts.self(), value);
2294 * Set one element of an Object array.
2296 static void SetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index, jobject jobj) {
2297 ScopedJniThreadState ts(env);
2299 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2300 if (!checkArrayElementBounds(arrayObj, index)) {
2304 //ALOGV("JNI: set element %d in array %p to %p", index, array, value);
2306 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
2307 dvmSetObjectArrayElement(arrayObj, index, obj);
2311 * Create a new array of primitive elements.
2313 #define NEW_PRIMITIVE_ARRAY(_artype, _jname, _typechar) \
2314 static _artype New##_jname##Array(JNIEnv* env, jsize length) { \
2315 ScopedJniThreadState ts(env); \
2316 ArrayObject* arrayObj = dvmAllocPrimitiveArray(_typechar, length, ALLOC_DEFAULT); \
2317 if (arrayObj == NULL) { \
2320 _artype result = (_artype) addLocalReference(ts.self(), (Object*) arrayObj); \
2321 dvmReleaseTrackedAlloc((Object*) arrayObj, NULL); \
2324 NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean, 'Z');
2325 NEW_PRIMITIVE_ARRAY(jbyteArray, Byte, 'B');
2326 NEW_PRIMITIVE_ARRAY(jcharArray, Char, 'C');
2327 NEW_PRIMITIVE_ARRAY(jshortArray, Short, 'S');
2328 NEW_PRIMITIVE_ARRAY(jintArray, Int, 'I');
2329 NEW_PRIMITIVE_ARRAY(jlongArray, Long, 'J');
2330 NEW_PRIMITIVE_ARRAY(jfloatArray, Float, 'F');
2331 NEW_PRIMITIVE_ARRAY(jdoubleArray, Double, 'D');
2334 * Get a pointer to a C array of primitive elements from an array object
2335 * of the matching type.
2337 * In a compacting GC, we either need to return a copy of the elements or
2338 * "pin" the memory. Otherwise we run the risk of native code using the
2339 * buffer as the destination of e.g. a blocking read() call that wakes up
2342 #define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
2343 static _ctype* Get##_jname##ArrayElements(JNIEnv* env, \
2344 _ctype##Array jarr, jboolean* isCopy) \
2346 ScopedJniThreadState ts(env); \
2347 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2348 pinPrimitiveArray(arrayObj); \
2349 _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2350 if (isCopy != NULL) { \
2351 *isCopy = JNI_FALSE; \
2357 * Release the storage locked down by the "get" function.
2359 * The spec says, "'mode' has no effect if 'elems' is not a copy of the
2360 * elements in 'array'." They apparently did not anticipate the need to
2363 #define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
2364 static void Release##_jname##ArrayElements(JNIEnv* env, \
2365 _ctype##Array jarr, _ctype* elems, jint mode) \
2367 UNUSED_PARAMETER(elems); \
2368 if (mode != JNI_COMMIT) { \
2369 ScopedJniThreadState ts(env); \
2370 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2371 unpinPrimitiveArray(arrayObj); \
2375 static void throwArrayRegionOutOfBounds(ArrayObject* arrayObj, jsize start,
2376 jsize len, const char* arrayIdentifier)
2378 dvmThrowExceptionFmt(gDvm.exArrayIndexOutOfBoundsException,
2379 "%s offset=%d length=%d %s.length=%d",
2380 arrayObj->clazz->descriptor, start, len, arrayIdentifier,
2385 * Copy a section of a primitive array to a buffer.
2387 #define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
2388 static void Get##_jname##ArrayRegion(JNIEnv* env, \
2389 _ctype##Array jarr, jsize start, jsize len, _ctype* buf) \
2391 ScopedJniThreadState ts(env); \
2392 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2393 _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2394 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
2395 throwArrayRegionOutOfBounds(arrayObj, start, len, "src"); \
2397 memcpy(buf, data + start, len * sizeof(_ctype)); \
2402 * Copy a section of a primitive array from a buffer.
2404 #define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
2405 static void Set##_jname##ArrayRegion(JNIEnv* env, \
2406 _ctype##Array jarr, jsize start, jsize len, const _ctype* buf) \
2408 ScopedJniThreadState ts(env); \
2409 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2410 _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2411 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
2412 throwArrayRegionOutOfBounds(arrayObj, start, len, "dst"); \
2414 memcpy(data + start, buf, len * sizeof(_ctype)); \
2420 * Get<Type>ArrayElements
2421 * Release<Type>ArrayElements
2422 * Get<Type>ArrayRegion
2423 * Set<Type>ArrayRegion
2425 #define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname) \
2426 GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
2427 RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
2428 GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \
2429 SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
2431 PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean);
2432 PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte);
2433 PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char);
2434 PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short);
2435 PRIMITIVE_ARRAY_FUNCTIONS(jint, Int);
2436 PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long);
2437 PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float);
2438 PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double);
2441 * Register one or more native functions in one class.
2443 * This can be called multiple times on the same method, allowing the
2444 * caller to redefine the method implementation at will.
2446 static jint RegisterNatives(JNIEnv* env, jclass jclazz,
2447 const JNINativeMethod* methods, jint nMethods)
2449 ScopedJniThreadState ts(env);
2451 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
2453 if (gDvm.verboseJni) {
2454 LOGI("[Registering JNI native methods for class %s]",
2458 for (int i = 0; i < nMethods; i++) {
2459 if (!dvmRegisterJNIMethod(clazz, methods[i].name,
2460 methods[i].signature, methods[i].fnPtr))
2469 * Un-register all native methods associated with the class.
2471 * The JNI docs refer to this as a way to reload/relink native libraries,
2472 * and say it "should not be used in normal native code". In particular,
2473 * there is no need to do this during shutdown, and you do not need to do
2474 * this before redefining a method implementation with RegisterNatives.
2476 * It's chiefly useful for a native "plugin"-style library that wasn't
2477 * loaded with System.loadLibrary() (since there's no way to unload those).
2478 * For example, the library could upgrade itself by:
2480 * 1. call UnregisterNatives to unbind the old methods
2481 * 2. ensure that no code is still executing inside it (somehow)
2482 * 3. dlclose() the library
2483 * 4. dlopen() the new library
2484 * 5. use RegisterNatives to bind the methods from the new library
2486 * The above can work correctly without the UnregisterNatives call, but
2487 * creates a window of opportunity in which somebody might try to call a
2488 * method that is pointing at unmapped memory, crashing the VM. In theory
2489 * the same guards that prevent dlclose() from unmapping executing code could
2490 * prevent that anyway, but with this we can be more thorough and also deal
2491 * with methods that only exist in the old or new form of the library (maybe
2492 * the lib wants to try the call and catch the UnsatisfiedLinkError).
2494 static jint UnregisterNatives(JNIEnv* env, jclass jclazz) {
2495 ScopedJniThreadState ts(env);
2497 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
2498 if (gDvm.verboseJni) {
2499 LOGI("[Unregistering JNI native methods for class %s]",
2502 dvmUnregisterJNINativeMethods(clazz);
2509 * We have to track all monitor enters and exits, so that we can undo any
2510 * outstanding synchronization before the thread exits.
2512 static jint MonitorEnter(JNIEnv* env, jobject jobj) {
2513 ScopedJniThreadState ts(env);
2514 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
2515 dvmLockObject(ts.self(), obj);
2516 trackMonitorEnter(ts.self(), obj);
2521 * Unlock the monitor.
2523 * Throws an IllegalMonitorStateException if the current thread
2524 * doesn't own the monitor. (dvmUnlockObject() takes care of the throw.)
2526 * According to the 1.6 spec, it's legal to call here with an exception
2527 * pending. If this fails, we'll stomp the original exception.
2529 static jint MonitorExit(JNIEnv* env, jobject jobj) {
2530 ScopedJniThreadState ts(env);
2531 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
2532 bool success = dvmUnlockObject(ts.self(), obj);
2534 trackMonitorExit(ts.self(), obj);
2536 return success ? JNI_OK : JNI_ERR;
2540 * Return the JavaVM interface associated with the current thread.
2542 static jint GetJavaVM(JNIEnv* env, JavaVM** vm) {
2543 ScopedJniThreadState ts(env);
2544 *vm = gDvmJni.jniVm;
2545 return (*vm == NULL) ? JNI_ERR : JNI_OK;
2549 * Copies "len" Unicode characters, from offset "start".
2551 static void GetStringRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, jchar* buf) {
2552 ScopedJniThreadState ts(env);
2553 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2554 int strLen = strObj->length();
2555 if (((start|len) < 0) || (start + len > strLen)) {
2556 dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
2559 memcpy(buf, strObj->chars() + start, len * sizeof(u2));
2563 * Translates "len" Unicode characters, from offset "start", into
2564 * modified UTF-8 encoding.
2566 static void GetStringUTFRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, char* buf) {
2567 ScopedJniThreadState ts(env);
2568 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2569 int strLen = strObj->length();
2570 if (((start|len) < 0) || (start + len > strLen)) {
2571 dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
2574 dvmGetStringUtfRegion(strObj, start, len, buf);
2578 * Get a raw pointer to array data.
2580 * The caller is expected to call "release" before doing any JNI calls
2581 * or blocking I/O operations.
2583 * We need to pin the memory or block GC.
2585 static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray jarr, jboolean* isCopy) {
2586 ScopedJniThreadState ts(env);
2587 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2588 pinPrimitiveArray(arrayObj);
2589 void* data = arrayObj->contents;
2590 if (UNLIKELY(isCopy != NULL)) {
2591 *isCopy = JNI_FALSE;
2597 * Release an array obtained with GetPrimitiveArrayCritical.
2599 static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray jarr, void* carray, jint mode) {
2600 if (mode != JNI_COMMIT) {
2601 ScopedJniThreadState ts(env);
2602 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2603 unpinPrimitiveArray(arrayObj);
2608 * Like GetStringChars, but with restricted use.
2610 static const jchar* GetStringCritical(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2611 ScopedJniThreadState ts(env);
2613 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2614 ArrayObject* strChars = strObj->array();
2616 pinPrimitiveArray(strChars);
2618 const u2* data = strObj->chars();
2619 if (isCopy != NULL) {
2620 *isCopy = JNI_FALSE;
2622 return (jchar*) data;
2626 * Like ReleaseStringChars, but with restricted use.
2628 static void ReleaseStringCritical(JNIEnv* env, jstring jstr, const jchar* carray) {
2629 ScopedJniThreadState ts(env);
2630 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2631 ArrayObject* strChars = strObj->array();
2632 unpinPrimitiveArray(strChars);
2636 * Create a new weak global reference.
2638 static jweak NewWeakGlobalRef(JNIEnv* env, jobject jobj) {
2639 ScopedJniThreadState ts(env);
2640 Object *obj = dvmDecodeIndirectRef(ts.self(), jobj);
2641 return (jweak) addWeakGlobalReference(obj);
2645 * Delete the specified weak global reference.
2647 static void DeleteWeakGlobalRef(JNIEnv* env, jweak wref) {
2648 ScopedJniThreadState ts(env);
2649 deleteWeakGlobalReference(wref);
2653 * Quick check for pending exceptions.
2655 * TODO: we should be able to skip the enter/exit macros here.
2657 static jboolean ExceptionCheck(JNIEnv* env) {
2658 ScopedJniThreadState ts(env);
2659 return dvmCheckException(ts.self());
2663 * Returns the type of the object referred to by "obj". It can be local,
2664 * global, or weak global.
2666 * In the current implementation, references can be global and local at
2667 * the same time, so while the return value is accurate it may not tell
2670 static jobjectRefType GetObjectRefType(JNIEnv* env, jobject jobj) {
2671 ScopedJniThreadState ts(env);
2672 return dvmGetJNIRefType(ts.self(), jobj);
2676 * Allocate and return a new java.nio.ByteBuffer for this block of memory.
2678 * "address" may not be NULL, and "capacity" must be > 0. (These are only
2679 * verified when CheckJNI is enabled.)
2681 static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
2682 ScopedJniThreadState ts(env);
2684 /* create an instance of java.nio.ReadWriteDirectByteBuffer */
2685 ClassObject* bufferClazz = gDvm.classJavaNioReadWriteDirectByteBuffer;
2686 if (!dvmIsClassInitialized(bufferClazz) && !dvmInitClass(bufferClazz)) {
2689 Object* newObj = dvmAllocObject(bufferClazz, ALLOC_DONT_TRACK);
2690 if (newObj == NULL) {
2693 /* call the constructor */
2694 jobject result = addLocalReference(ts.self(), newObj);
2696 dvmCallMethod(ts.self(), gDvm.methJavaNioReadWriteDirectByteBuffer_init,
2697 newObj, &unused, (jint) address, (jint) capacity);
2698 if (dvmGetException(ts.self()) != NULL) {
2699 deleteLocalReference(ts.self(), result);
2706 * Get the starting address of the buffer for the specified java.nio.Buffer.
2708 * If this is not a "direct" buffer, we return NULL.
2710 static void* GetDirectBufferAddress(JNIEnv* env, jobject jbuf) {
2711 ScopedJniThreadState ts(env);
2713 // All Buffer objects have an effectiveDirectAddress field.
2714 Object* bufObj = dvmDecodeIndirectRef(ts.self(), jbuf);
2715 return (void*) dvmGetFieldInt(bufObj, gDvm.offJavaNioBuffer_effectiveDirectAddress);
2719 * Get the capacity of the buffer for the specified java.nio.Buffer.
2721 * Returns -1 if the object is not a direct buffer. (We actually skip
2722 * this check, since it's expensive to determine, and just return the
2723 * capacity regardless.)
2725 static jlong GetDirectBufferCapacity(JNIEnv* env, jobject jbuf) {
2726 ScopedJniThreadState ts(env);
2729 * The capacity is always in the Buffer.capacity field.
2731 * (The "check" version should verify that this is actually a Buffer,
2732 * but we're not required to do so here.)
2734 Object* buf = dvmDecodeIndirectRef(ts.self(), jbuf);
2735 return dvmGetFieldInt(buf, gDvm.offJavaNioBuffer_capacity);
2740 * ===========================================================================
2741 * JNI invocation functions
2742 * ===========================================================================
2746 * Handle AttachCurrentThread{AsDaemon}.
2748 * We need to make sure the VM is actually running. For example, if we start
2749 * up, issue an Attach, and the VM exits almost immediately, by the time the
2750 * attaching happens the VM could already be shutting down.
2752 * It's hard to avoid a race condition here because we don't want to hold
2753 * a lock across the entire operation. What we can do is temporarily
2754 * increment the thread count to prevent a VM exit.
2756 * This could potentially still have problems if a daemon thread calls here
2757 * while the VM is shutting down. dvmThreadSelf() will work, since it just
2758 * uses pthread TLS, but dereferencing "vm" could fail. Such is life when
2759 * you shut down a VM while threads are still running inside it.
2761 * Remember that some code may call this as a way to find the per-thread
2762 * JNIEnv pointer. Don't do excess work for that case.
2764 static jint attachThread(JavaVM* vm, JNIEnv** p_env, void* thr_args, bool isDaemon) {
2765 JavaVMAttachArgs* args = (JavaVMAttachArgs*) thr_args;
2768 * Return immediately if we're already one with the VM.
2770 Thread* self = dvmThreadSelf();
2772 *p_env = self->jniEnv;
2777 * No threads allowed in zygote mode.
2783 /* increment the count to keep the VM from bailing while we run */
2784 dvmLockThreadList(NULL);
2785 if (gDvm.nonDaemonThreadCount == 0) {
2787 ALOGV("Refusing to attach thread '%s' -- VM is shutting down",
2788 (thr_args == NULL) ? "(unknown)" : args->name);
2789 dvmUnlockThreadList();
2792 gDvm.nonDaemonThreadCount++;
2793 dvmUnlockThreadList();
2795 /* tweak the JavaVMAttachArgs as needed */
2796 JavaVMAttachArgs argsCopy;
2798 /* allow the v1.1 calling convention */
2799 argsCopy.version = JNI_VERSION_1_2;
2800 argsCopy.name = NULL;
2801 argsCopy.group = (jobject) dvmGetMainThreadGroup();
2803 assert(args->version >= JNI_VERSION_1_2);
2805 argsCopy.version = args->version;
2806 argsCopy.name = args->name;
2807 if (args->group != NULL) {
2808 argsCopy.group = (jobject) dvmDecodeIndirectRef(NULL, args->group);
2810 argsCopy.group = (jobject) dvmGetMainThreadGroup();
2814 bool result = dvmAttachCurrentThread(&argsCopy, isDaemon);
2816 /* restore the count */
2817 dvmLockThreadList(NULL);
2818 gDvm.nonDaemonThreadCount--;
2819 dvmUnlockThreadList();
2822 * Change the status to indicate that we're out in native code. This
2823 * call is not guarded with state-change macros, so we have to do it
2827 self = dvmThreadSelf();
2828 assert(self != NULL);
2829 dvmChangeStatus(self, THREAD_NATIVE);
2830 *p_env = self->jniEnv;
2838 * Attach the current thread to the VM. If the thread is already attached,
2841 static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
2842 return attachThread(vm, p_env, thr_args, false);
2846 * Like AttachCurrentThread, but set the "daemon" flag.
2848 static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args)
2850 return attachThread(vm, p_env, thr_args, true);
2854 * Dissociate the current thread from the VM.
2856 static jint DetachCurrentThread(JavaVM* vm) {
2857 Thread* self = dvmThreadSelf();
2859 /* not attached, can't do anything */
2863 /* switch to "running" to check for suspension */
2864 dvmChangeStatus(self, THREAD_RUNNING);
2866 /* detach the thread */
2867 dvmDetachCurrentThread();
2869 /* (no need to change status back -- we have no status) */
2874 * If current thread is attached to VM, return the associated JNIEnv.
2875 * Otherwise, stuff NULL in and return JNI_EDETACHED.
2877 * JVMTI overloads this by specifying a magic value for "version", so we
2878 * do want to check that here.
2880 static jint GetEnv(JavaVM* vm, void** env, jint version) {
2881 Thread* self = dvmThreadSelf();
2883 if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6) {
2884 return JNI_EVERSION;
2890 /* TODO: status change is probably unnecessary */
2891 dvmChangeStatus(self, THREAD_RUNNING);
2892 *env = (void*) dvmGetThreadJNIEnv(self);
2893 dvmChangeStatus(self, THREAD_NATIVE);
2895 return (*env != NULL) ? JNI_OK : JNI_EDETACHED;
2899 * Destroy the VM. This may be called from any thread.
2901 * If the current thread is attached, wait until the current thread is
2902 * the only non-daemon user-level thread. If the current thread is not
2903 * attached, we attach it and do the processing as usual. (If the attach
2904 * fails, it's probably because all the non-daemon threads have already
2905 * exited and the VM doesn't want to let us back in.)
2907 * TODO: we don't really deal with the situation where more than one thread
2908 * has called here. One thread wins, the other stays trapped waiting on
2909 * the condition variable forever. Not sure this situation is interesting
2912 static jint DestroyJavaVM(JavaVM* vm) {
2913 JavaVMExt* ext = (JavaVMExt*) vm;
2918 if (gDvm.verboseShutdown) {
2919 LOGD("DestroyJavaVM waiting for non-daemon threads to exit");
2923 * Sleep on a condition variable until it's okay to exit.
2925 Thread* self = dvmThreadSelf();
2928 if (AttachCurrentThread(vm, &tmpEnv, NULL) != JNI_OK) {
2929 ALOGV("Unable to reattach main for Destroy; assuming VM is shutting down (count=%d)",
2930 gDvm.nonDaemonThreadCount);
2933 ALOGV("Attached to wait for shutdown in Destroy");
2936 dvmChangeStatus(self, THREAD_VMWAIT);
2938 dvmLockThreadList(self);
2939 gDvm.nonDaemonThreadCount--; // remove current thread from count
2941 while (gDvm.nonDaemonThreadCount > 0) {
2942 pthread_cond_wait(&gDvm.vmExitCond, &gDvm.threadListLock);
2945 dvmUnlockThreadList();
2949 // TODO: call System.exit() to run any registered shutdown hooks
2950 // (this may not return -- figure out how this should work)
2952 if (gDvm.verboseShutdown) {
2953 LOGD("DestroyJavaVM shutting VM down");
2957 // TODO - free resources associated with JNI-attached daemon threads
2966 * ===========================================================================
2968 * ===========================================================================
2971 static const struct JNINativeInterface gNativeInterface = {
2982 FromReflectedMethod,
3006 EnsureLocalCapacity,
3049 CallNonvirtualObjectMethod,
3050 CallNonvirtualObjectMethodV,
3051 CallNonvirtualObjectMethodA,
3052 CallNonvirtualBooleanMethod,
3053 CallNonvirtualBooleanMethodV,
3054 CallNonvirtualBooleanMethodA,
3055 CallNonvirtualByteMethod,
3056 CallNonvirtualByteMethodV,
3057 CallNonvirtualByteMethodA,
3058 CallNonvirtualCharMethod,
3059 CallNonvirtualCharMethodV,
3060 CallNonvirtualCharMethodA,
3061 CallNonvirtualShortMethod,
3062 CallNonvirtualShortMethodV,
3063 CallNonvirtualShortMethodA,
3064 CallNonvirtualIntMethod,
3065 CallNonvirtualIntMethodV,
3066 CallNonvirtualIntMethodA,
3067 CallNonvirtualLongMethod,
3068 CallNonvirtualLongMethodV,
3069 CallNonvirtualLongMethodA,
3070 CallNonvirtualFloatMethod,
3071 CallNonvirtualFloatMethodV,
3072 CallNonvirtualFloatMethodA,
3073 CallNonvirtualDoubleMethod,
3074 CallNonvirtualDoubleMethodV,
3075 CallNonvirtualDoubleMethodA,
3076 CallNonvirtualVoidMethod,
3077 CallNonvirtualVoidMethodV,
3078 CallNonvirtualVoidMethodA,
3103 CallStaticObjectMethod,
3104 CallStaticObjectMethodV,
3105 CallStaticObjectMethodA,
3106 CallStaticBooleanMethod,
3107 CallStaticBooleanMethodV,
3108 CallStaticBooleanMethodA,
3109 CallStaticByteMethod,
3110 CallStaticByteMethodV,
3111 CallStaticByteMethodA,
3112 CallStaticCharMethod,
3113 CallStaticCharMethodV,
3114 CallStaticCharMethodA,
3115 CallStaticShortMethod,
3116 CallStaticShortMethodV,
3117 CallStaticShortMethodA,
3118 CallStaticIntMethod,
3119 CallStaticIntMethodV,
3120 CallStaticIntMethodA,
3121 CallStaticLongMethod,
3122 CallStaticLongMethodV,
3123 CallStaticLongMethodA,
3124 CallStaticFloatMethod,
3125 CallStaticFloatMethodV,
3126 CallStaticFloatMethodA,
3127 CallStaticDoubleMethod,
3128 CallStaticDoubleMethodV,
3129 CallStaticDoubleMethodA,
3130 CallStaticVoidMethod,
3131 CallStaticVoidMethodV,
3132 CallStaticVoidMethodA,
3136 GetStaticObjectField,
3137 GetStaticBooleanField,
3140 GetStaticShortField,
3143 GetStaticFloatField,
3144 GetStaticDoubleField,
3146 SetStaticObjectField,
3147 SetStaticBooleanField,
3150 SetStaticShortField,
3153 SetStaticFloatField,
3154 SetStaticDoubleField,
3165 ReleaseStringUTFChars,
3169 GetObjectArrayElement,
3170 SetObjectArrayElement,
3181 GetBooleanArrayElements,
3182 GetByteArrayElements,
3183 GetCharArrayElements,
3184 GetShortArrayElements,
3185 GetIntArrayElements,
3186 GetLongArrayElements,
3187 GetFloatArrayElements,
3188 GetDoubleArrayElements,
3190 ReleaseBooleanArrayElements,
3191 ReleaseByteArrayElements,
3192 ReleaseCharArrayElements,
3193 ReleaseShortArrayElements,
3194 ReleaseIntArrayElements,
3195 ReleaseLongArrayElements,
3196 ReleaseFloatArrayElements,
3197 ReleaseDoubleArrayElements,
3199 GetBooleanArrayRegion,
3202 GetShortArrayRegion,
3205 GetFloatArrayRegion,
3206 GetDoubleArrayRegion,
3207 SetBooleanArrayRegion,
3210 SetShortArrayRegion,
3213 SetFloatArrayRegion,
3214 SetDoubleArrayRegion,
3227 GetPrimitiveArrayCritical,
3228 ReleasePrimitiveArrayCritical,
3231 ReleaseStringCritical,
3234 DeleteWeakGlobalRef,
3238 NewDirectByteBuffer,
3239 GetDirectBufferAddress,
3240 GetDirectBufferCapacity,
3245 static const struct JNIInvokeInterface gInvokeInterface = {
3251 AttachCurrentThread,
3252 DetachCurrentThread,
3256 AttachCurrentThreadAsDaemon,
3260 * ===========================================================================
3262 * ===========================================================================
3266 * Create a new JNIEnv struct and add it to the VM's list.
3268 * "self" will be NULL for the main thread, since the VM hasn't started
3269 * yet; the value will be filled in later.
3271 JNIEnv* dvmCreateJNIEnv(Thread* self) {
3272 JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
3275 // LOGI("Ent CreateJNIEnv: threadid=%d %p", self->threadId, self);
3279 JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
3280 newEnv->funcTable = &gNativeInterface;
3282 dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
3283 assert(newEnv->envThreadId != 0);
3285 /* make it obvious if we fail to initialize these later */
3286 newEnv->envThreadId = 0x77777775;
3287 newEnv->self = (Thread*) 0x77777779;
3289 if (gDvmJni.useCheckJni) {
3290 dvmUseCheckedJniEnv(newEnv);
3293 ScopedPthreadMutexLock lock(&vm->envListLock);
3295 /* insert at head of list */
3296 newEnv->next = vm->envList;
3297 assert(newEnv->prev == NULL);
3298 if (vm->envList == NULL) {
3299 // rare, but possible
3300 vm->envList = newEnv;
3302 vm->envList->prev = newEnv;
3304 vm->envList = newEnv;
3307 // LOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self);
3308 return (JNIEnv*) newEnv;
3312 * Remove a JNIEnv struct from the list and free it.
3314 void dvmDestroyJNIEnv(JNIEnv* env) {
3319 //LOGI("Ent DestroyJNIEnv: threadid=%d %p", self->threadId, self);
3321 JNIEnvExt* extEnv = (JNIEnvExt*) env;
3322 JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
3324 ScopedPthreadMutexLock lock(&vm->envListLock);
3326 if (extEnv == vm->envList) {
3327 assert(extEnv->prev == NULL);
3328 vm->envList = extEnv->next;
3330 assert(extEnv->prev != NULL);
3331 extEnv->prev->next = extEnv->next;
3333 if (extEnv->next != NULL) {
3334 extEnv->next->prev = extEnv->prev;
3338 //LOGI("Xit DestroyJNIEnv: threadid=%d %p", self->threadId, self);
3342 * Enable "checked JNI" after the VM has partially started. This must
3343 * only be called in "zygote" mode, when we have one thread running.
3345 * This doesn't attempt to rewrite the JNI call bridge associated with
3346 * native methods, so we won't get those checks for any methods that have
3347 * already been resolved.
3349 void dvmLateEnableCheckedJni() {
3350 JNIEnvExt* extEnv = dvmGetJNIEnvForThread();
3351 if (extEnv == NULL) {
3352 LOGE("dvmLateEnableCheckedJni: thread has no JNIEnv");
3355 JavaVMExt* extVm = (JavaVMExt*) gDvmJni.jniVm;
3356 assert(extVm != NULL);
3358 if (!gDvmJni.useCheckJni) {
3359 LOGD("Late-enabling CheckJNI");
3360 dvmUseCheckedJniVm(extVm);
3361 dvmUseCheckedJniEnv(extEnv);
3363 LOGD("Not late-enabling CheckJNI (already on)");
3370 jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
3375 * Return a buffer full of created VMs.
3377 * We always have zero or one.
3379 jint JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs) {
3380 if (gDvmJni.jniVm != NULL) {
3383 *vmBuf++ = gDvmJni.jniVm;
3392 * Create a new VM instance.
3394 * The current thread becomes the main VM thread. We return immediately,
3395 * which effectively means the caller is executing in a native method.
3397 jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
3398 const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args;
3399 if (args->version < JNI_VERSION_1_2) {
3400 return JNI_EVERSION;
3403 // TODO: don't allow creation of multiple VMs -- one per customer for now
3405 /* zero globals; not strictly necessary the first time a VM is started */
3406 memset(&gDvm, 0, sizeof(gDvm));
3409 * Set up structures for JNIEnv and VM.
3411 JavaVMExt* pVM = (JavaVMExt*) malloc(sizeof(JavaVMExt));
3412 memset(pVM, 0, sizeof(JavaVMExt));
3413 pVM->funcTable = &gInvokeInterface;
3414 pVM->envList = NULL;
3415 dvmInitMutex(&pVM->envListLock);
3417 UniquePtr<const char*[]> argv(new const char*[args->nOptions]);
3418 memset(argv.get(), 0, sizeof(char*) * (args->nOptions));
3421 * Convert JNI args to argv.
3423 * We have to pull out vfprintf/exit/abort, because they use the
3424 * "extraInfo" field to pass function pointer "hooks" in. We also
3425 * look for the -Xcheck:jni stuff here.
3428 for (int i = 0; i < args->nOptions; i++) {
3429 const char* optStr = args->options[i].optionString;
3430 if (optStr == NULL) {
3431 dvmFprintf(stderr, "ERROR: CreateJavaVM failed: argument %d was NULL\n", i);
3433 } else if (strcmp(optStr, "vfprintf") == 0) {
3434 gDvm.vfprintfHook = (int (*)(FILE *, const char*, va_list))args->options[i].extraInfo;
3435 } else if (strcmp(optStr, "exit") == 0) {
3436 gDvm.exitHook = (void (*)(int)) args->options[i].extraInfo;
3437 } else if (strcmp(optStr, "abort") == 0) {
3438 gDvm.abortHook = (void (*)(void))args->options[i].extraInfo;
3439 } else if (strcmp(optStr, "sensitiveThread") == 0) {
3440 gDvm.isSensitiveThreadHook = (bool (*)(void))args->options[i].extraInfo;
3441 } else if (strcmp(optStr, "-Xcheck:jni") == 0) {
3442 gDvmJni.useCheckJni = true;
3443 } else if (strncmp(optStr, "-Xjniopts:", 10) == 0) {
3444 char* jniOpts = strdup(optStr + 10);
3445 size_t jniOptCount = 1;
3446 for (char* p = jniOpts; *p != 0; ++p) {
3452 char* jniOpt = jniOpts;
3453 for (size_t i = 0; i < jniOptCount; ++i) {
3454 if (strcmp(jniOpt, "warnonly") == 0) {
3455 gDvmJni.warnOnly = true;
3456 } else if (strcmp(jniOpt, "forcecopy") == 0) {
3457 gDvmJni.forceCopy = true;
3458 } else if (strcmp(jniOpt, "logThirdPartyJni") == 0) {
3459 gDvmJni.logThirdPartyJni = true;
3461 dvmFprintf(stderr, "ERROR: CreateJavaVM failed: unknown -Xjniopts option '%s'\n",
3465 jniOpt += strlen(jniOpt) + 1;
3469 /* regular option */
3470 argv[argc++] = optStr;
3474 if (gDvmJni.useCheckJni) {
3475 dvmUseCheckedJniVm(pVM);
3478 if (gDvmJni.jniVm != NULL) {
3479 dvmFprintf(stderr, "ERROR: Dalvik only supports one VM per process\n");
3482 gDvmJni.jniVm = (JavaVM*) pVM;
3485 * Create a JNIEnv for the main thread. We need to have something set up
3486 * here because some of the class initialization we do when starting
3487 * up the VM will call into native code.
3489 JNIEnvExt* pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);
3491 /* Initialize VM. */
3492 gDvm.initializing = true;
3493 std::string status =
3494 dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);
3495 gDvm.initializing = false;
3497 if (!status.empty()) {
3500 LOGW("CreateJavaVM failed: %s", status.c_str());
3505 * Success! Return stuff to caller.
3507 dvmChangeStatus(NULL, THREAD_NATIVE);
3508 *p_env = (JNIEnv*) pEnv;
3509 *p_vm = (JavaVM*) pVM;
3510 ALOGV("CreateJavaVM succeeded");