2 * Copyright (C) 2008 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * Dalvik implementation of JNI interfaces.
21 #include "JniInternal.h"
23 #include "ScopedPthreadMutexLock.h"
24 #include "UniquePtr.h"
31 Native methods and interaction with the GC
33 All JNI methods must start by changing their thread status to
34 THREAD_RUNNING, and finish by changing it back to THREAD_NATIVE before
35 returning to native code. The switch to "running" triggers a thread
38 With a rudimentary GC we should be able to skip the status change for
39 simple functions, e.g. IsSameObject, GetJavaVM, GetStringLength, maybe
40 even access to fields with primitive types. Our options are more limited
43 For performance reasons we do as little error-checking as possible here.
44 For example, we don't check to make sure the correct type of Object is
45 passed in when setting a field, and we don't prevent you from storing
46 new values in a "final" field. Such things are best handled in the
47 "check" version. For actions that are common, dangerous, and must be
48 checked at runtime, such as array bounds checks, we do the tests here.
51 General notes on local/global reference tracking
53 JNI provides explicit control over natively-held references that the GC
54 needs to know about. These can be local, in which case they're released
55 when the native method returns into the VM, or global, which are held
56 until explicitly released. (There are also weak-global references,
57 which have the lifespan and visibility of global references, but the
58 object they refer to may be collected.)
60 The references can be created with explicit JNI NewLocalRef / NewGlobalRef
61 calls. The former is very unusual, the latter is reasonably common
62 (e.g. for caching references to class objects).
64 Local references are most often created as a side-effect of JNI functions.
65 For example, the AllocObject/NewObject functions must create local
66 references to the objects returned, because nothing else in the GC root
67 set has a reference to the new objects.
69 The most common mode of operation is for a method to create zero or
70 more local references and return. Explicit "local delete" operations
71 are expected to be exceedingly rare, except when walking through an
72 object array, and the Push/PopLocalFrame calls are expected to be used
73 infrequently. For efficient operation, we want to add new local refs
74 with a simple store/increment operation; to avoid infinite growth in
75 pathological situations, we need to reclaim the space used by deleted
78 If we just want to maintain a list for the GC root set, we can use an
79 expanding append-only array that compacts when objects are deleted.
80 In typical situations, e.g. running through an array of objects, we will
81 be deleting one of the most recently added entries, so we can minimize
82 the number of elements moved (or avoid having to move any).
84 If we want to conceal the pointer values from native code, which is
85 necessary to allow the GC to move JNI-referenced objects around, then we
86 have to use a more complicated indirection mechanism.
88 The spec says, "Local references are only valid in the thread in which
89 they are created. The native code must not pass local references from
90 one thread to another."
95 For some large chunks of data, notably primitive arrays and String data,
96 JNI allows the VM to choose whether it wants to pin the array object or
97 make a copy. We currently pin the memory for better execution performance.
99 TODO: we're using simple root set references to pin primitive array data,
100 because they have the property we need (i.e. the pointer we return is
101 guaranteed valid until we explicitly release it). However, if we have a
102 compacting GC and don't want to pin all memory held by all global refs,
103 we need to treat these differently.
106 Global reference tracking
108 There should be a small "active" set centered around the most-recently
111 Because it's global, access to it has to be synchronized. Additions and
112 removals require grabbing a mutex. If the table serves as an indirection
113 mechanism (i.e. it's not just a list for the benefit of the garbage
114 collector), reference lookups may also require grabbing a mutex.
116 The JNI spec does not define any sort of limit, so the list must be able
117 to expand to a reasonable size. It may be useful to log significant
118 increases in usage to help identify resource leaks.
121 Weak-global reference tracking
126 Local reference tracking
128 Each Thread/JNIEnv points to an IndirectRefTable.
130 We implement Push/PopLocalFrame with actual stack frames. Before a JNI
131 frame gets popped, we set "nextEntry" to the "top" pointer of the current
132 frame, effectively releasing the references.
134 The GC will scan all references in the table.
138 static void ReportJniError() {
139 dvmDumpThread(dvmThreadSelf(), false);
143 #ifdef WITH_JNI_STACK_CHECK
144 # define COMPUTE_STACK_SUM(_self) computeStackSum(_self);
145 # define CHECK_STACK_SUM(_self) checkStackSum(_self);
148 * Compute a CRC on the entire interpreted stack.
150 * Would be nice to compute it on "self" as well, but there are parts of
151 * the Thread that can be altered by other threads (e.g. prev/next pointers).
153 static void computeStackSum(Thread* self) {
154 const u1* low = (const u1*)SAVEAREA_FROM_FP(self->interpSave.curFrame);
155 u4 crc = dvmInitCrc32();
157 crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
158 self->stackCrc = crc;
162 * Compute a CRC on the entire interpreted stack, and compare it to what
163 * we previously computed.
165 * We can execute JNI directly from native code without calling in from
166 * interpreted code during VM initialization and immediately after JNI
167 * thread attachment. Another opportunity exists during JNI_OnLoad. Rather
168 * than catching these cases we just ignore them here, which is marginally
169 * less accurate but reduces the amount of code we have to touch with #ifdefs.
171 static void checkStackSum(Thread* self) {
172 const u1* low = (const u1*)SAVEAREA_FROM_FP(self->interpSave.curFrame);
173 u4 stackCrc = self->stackCrc;
175 u4 crc = dvmInitCrc32();
176 crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
177 if (crc != stackCrc) {
178 const Method* meth = dvmGetCurrentJNIMethod();
179 if (dvmComputeExactFrameDepth(self->interpSave.curFrame) == 1) {
180 ALOGD("JNI: bad stack CRC (0x%08x) -- okay during init", stackCrc);
181 } else if (strcmp(meth->name, "nativeLoad") == 0 &&
182 (strcmp(meth->clazz->descriptor, "Ljava/lang/Runtime;") == 0)) {
183 ALOGD("JNI: bad stack CRC (0x%08x) -- okay during JNI_OnLoad", stackCrc);
185 ALOGW("JNI: bad stack CRC (%08x vs %08x)", crc, stackCrc);
189 self->stackCrc = (u4) -1; /* make logic errors more noticeable */
193 # define COMPUTE_STACK_SUM(_self) ((void)0)
194 # define CHECK_STACK_SUM(_self) ((void)0)
199 * ===========================================================================
201 * ===========================================================================
205 * Entry/exit processing for all JNI calls.
207 * We skip the (curiously expensive) thread-local storage lookup on our Thread*.
208 * If the caller has passed the wrong JNIEnv in, we're going to be accessing unsynchronized
209 * structures from more than one thread, and things are going to fail
210 * in bizarre ways. This is only sensible if the native code has been
211 * fully exercised with CheckJNI enabled.
213 class ScopedJniThreadState {
215 explicit ScopedJniThreadState(JNIEnv* env) {
216 mSelf = ((JNIEnvExt*) env)->self;
218 if (UNLIKELY(gDvmJni.workAroundAppJniBugs)) {
219 // When emulating direct pointers with indirect references, it's critical
220 // that we use the correct per-thread indirect reference table.
221 Thread* self = gDvmJni.workAroundAppJniBugs ? dvmThreadSelf() : mSelf;
223 ALOGE("JNI ERROR: env->self != thread-self (%p vs. %p); auto-correcting", mSelf, self);
228 CHECK_STACK_SUM(mSelf);
229 dvmChangeStatus(mSelf, THREAD_RUNNING);
232 ~ScopedJniThreadState() {
233 dvmChangeStatus(mSelf, THREAD_NATIVE);
234 COMPUTE_STACK_SUM(mSelf);
237 inline Thread* self() {
244 // Disallow copy and assignment.
245 ScopedJniThreadState(const ScopedJniThreadState&);
246 void operator=(const ScopedJniThreadState&);
249 #define kGlobalRefsTableInitialSize 512
250 #define kGlobalRefsTableMaxSize 51200 /* arbitrary, must be < 64K */
252 #define kWeakGlobalRefsTableInitialSize 16
254 #define kPinTableInitialSize 16
255 #define kPinTableMaxSize 1024
256 #define kPinComplainThreshold 10
258 bool dvmJniStartup() {
259 if (!gDvm.jniGlobalRefTable.init(kGlobalRefsTableInitialSize,
260 kGlobalRefsTableMaxSize,
261 kIndirectKindGlobal)) {
264 if (!gDvm.jniWeakGlobalRefTable.init(kWeakGlobalRefsTableInitialSize,
265 kGlobalRefsTableMaxSize,
266 kIndirectKindWeakGlobal)) {
270 dvmInitMutex(&gDvm.jniGlobalRefLock);
271 dvmInitMutex(&gDvm.jniWeakGlobalRefLock);
273 if (!dvmInitReferenceTable(&gDvm.jniPinRefTable, kPinTableInitialSize, kPinTableMaxSize)) {
277 dvmInitMutex(&gDvm.jniPinRefLock);
282 void dvmJniShutdown() {
283 gDvm.jniGlobalRefTable.destroy();
284 gDvm.jniWeakGlobalRefTable.destroy();
285 dvmClearReferenceTable(&gDvm.jniPinRefTable);
289 * Find the JNIEnv associated with the current thread.
291 * Currently stored in the Thread struct. Could also just drop this into
292 * thread-local storage.
294 JNIEnvExt* dvmGetJNIEnvForThread() {
295 Thread* self = dvmThreadSelf();
299 return (JNIEnvExt*) dvmGetThreadJNIEnv(self);
303 * Convert an indirect reference to an Object reference. The indirect
304 * reference may be local, global, or weak-global.
306 * If "jobj" is NULL, or is a weak global reference whose reference has
307 * been cleared, this returns NULL. If jobj is an invalid indirect
308 * reference, kInvalidIndirectRefObject is returned.
310 * Note "env" may be NULL when decoding global references.
312 Object* dvmDecodeIndirectRef(Thread* self, jobject jobj) {
317 switch (indirectRefKind(jobj)) {
318 case kIndirectKindLocal:
320 Object* result = self->jniLocalRefTable.get(jobj);
321 if (UNLIKELY(result == NULL)) {
322 ALOGE("JNI ERROR (app bug): use of deleted local reference (%p)", jobj);
327 case kIndirectKindGlobal:
329 // TODO: find a way to avoid the mutex activity here
330 IndirectRefTable* pRefTable = &gDvm.jniGlobalRefTable;
331 ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
332 Object* result = pRefTable->get(jobj);
333 if (UNLIKELY(result == NULL)) {
334 ALOGE("JNI ERROR (app bug): use of deleted global reference (%p)", jobj);
339 case kIndirectKindWeakGlobal:
341 // TODO: find a way to avoid the mutex activity here
342 IndirectRefTable* pRefTable = &gDvm.jniWeakGlobalRefTable;
343 ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
344 Object* result = pRefTable->get(jobj);
345 if (result == kClearedJniWeakGlobal) {
347 } else if (UNLIKELY(result == NULL)) {
348 ALOGE("JNI ERROR (app bug): use of deleted weak global reference (%p)", jobj);
353 case kIndirectKindInvalid:
355 if (UNLIKELY(gDvmJni.workAroundAppJniBugs)) {
356 // Assume an invalid local reference is actually a direct pointer.
357 return reinterpret_cast<Object*>(jobj);
359 ALOGW("Invalid indirect reference %p in decodeIndirectRef", jobj);
361 return kInvalidIndirectRefObject;
365 static void AddLocalReferenceFailure(IndirectRefTable* pRefTable) {
366 pRefTable->dump("JNI local");
367 ALOGE("Failed adding to JNI local ref table (has %zd entries)", pRefTable->capacity());
368 ReportJniError(); // spec says call FatalError; this is equivalent
372 * Add a local reference for an object to the current stack frame. When
373 * the native function returns, the reference will be discarded.
375 * We need to allow the same reference to be added multiple times.
377 * This will be called on otherwise unreferenced objects. We cannot do
378 * GC allocations here, and it's best if we don't grab a mutex.
380 static inline jobject addLocalReference(Thread* self, Object* obj) {
385 IndirectRefTable* pRefTable = &self->jniLocalRefTable;
386 void* curFrame = self->interpSave.curFrame;
387 u4 cookie = SAVEAREA_FROM_FP(curFrame)->xtra.localRefCookie;
388 jobject jobj = (jobject) pRefTable->add(cookie, obj);
389 if (UNLIKELY(jobj == NULL)) {
390 AddLocalReferenceFailure(pRefTable);
393 if (UNLIKELY(gDvmJni.workAroundAppJniBugs)) {
394 // Hand out direct pointers to support broken old apps.
395 return reinterpret_cast<jobject>(obj);
401 * Ensure that at least "capacity" references can be held in the local
402 * refs table of the current thread.
404 static bool ensureLocalCapacity(Thread* self, int capacity) {
405 int numEntries = self->jniLocalRefTable.capacity();
406 // TODO: this isn't quite right, since "numEntries" includes holes
407 return ((kJniLocalRefMax - numEntries) >= capacity);
411 * Explicitly delete a reference from the local list.
413 static void deleteLocalReference(Thread* self, jobject jobj) {
418 IndirectRefTable* pRefTable = &self->jniLocalRefTable;
419 void* curFrame = self->interpSave.curFrame;
420 u4 cookie = SAVEAREA_FROM_FP(curFrame)->xtra.localRefCookie;
421 if (!pRefTable->remove(cookie, jobj)) {
423 * Attempting to delete a local reference that is not in the
424 * topmost local reference frame is a no-op. DeleteLocalRef returns
425 * void and doesn't throw any exceptions, but we should probably
426 * complain about it so the user will notice that things aren't
427 * going quite the way they expect.
429 ALOGW("JNI WARNING: DeleteLocalRef(%p) failed to find entry", jobj);
434 * Add a global reference for an object.
436 * We may add the same object more than once. Add/remove calls are paired,
437 * so it needs to appear on the list multiple times.
439 static jobject addGlobalReference(Object* obj) {
444 //ALOGI("adding obj=%p", obj);
445 //dvmDumpThread(dvmThreadSelf(), false);
447 if (false && dvmIsClassObject((Object*)obj)) {
448 ClassObject* clazz = (ClassObject*) obj;
450 ALOGI("Adding global ref on class %s", clazz->descriptor);
451 dvmDumpThread(dvmThreadSelf(), false);
453 if (false && ((Object*)obj)->clazz == gDvm.classJavaLangString) {
454 StringObject* strObj = (StringObject*) obj;
455 char* str = dvmCreateCstrFromString(strObj);
456 if (strcmp(str, "sync-response") == 0) {
458 ALOGI("Adding global ref on string '%s'", str);
459 dvmDumpThread(dvmThreadSelf(), false);
464 if (false && ((Object*)obj)->clazz == gDvm.classArrayByte) {
465 ArrayObject* arrayObj = (ArrayObject*) obj;
466 if (arrayObj->length == 8192 /*&&
467 dvmReferenceTableEntries(&gDvm.jniGlobalRefTable) > 400*/)
469 ALOGI("Adding global ref on byte array %p (len=%d)",
470 arrayObj, arrayObj->length);
471 dvmDumpThread(dvmThreadSelf(), false);
475 ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
478 * Throwing an exception on failure is problematic, because JNI code
479 * may not be expecting an exception, and things sort of cascade. We
480 * want to have a hard limit to catch leaks during debugging, but this
481 * otherwise needs to expand until memory is consumed. As a practical
482 * matter, if we have many thousands of global references, chances are
483 * we're either leaking global ref table entries or we're going to
484 * run out of space in the GC heap.
486 jobject jobj = (jobject) gDvm.jniGlobalRefTable.add(IRT_FIRST_SEGMENT, obj);
488 gDvm.jniGlobalRefTable.dump("JNI global");
489 ALOGE("Failed adding to JNI global ref table (%zd entries)",
490 gDvm.jniGlobalRefTable.capacity());
494 LOGVV("GREF add %p (%s.%s)", obj,
495 dvmGetCurrentJNIMethod()->clazz->descriptor,
496 dvmGetCurrentJNIMethod()->name);
501 static jobject addWeakGlobalReference(Object* obj) {
506 ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
507 IndirectRefTable *table = &gDvm.jniWeakGlobalRefTable;
508 jobject jobj = (jobject) table->add(IRT_FIRST_SEGMENT, obj);
510 gDvm.jniWeakGlobalRefTable.dump("JNI weak global");
511 ALOGE("Failed adding to JNI weak global ref table (%zd entries)", table->capacity());
517 static void deleteWeakGlobalReference(jobject jobj) {
522 ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
523 IndirectRefTable *table = &gDvm.jniWeakGlobalRefTable;
524 if (!table->remove(IRT_FIRST_SEGMENT, jobj)) {
525 ALOGW("JNI: DeleteWeakGlobalRef(%p) failed to find entry", jobj);
530 * Remove a global reference. In most cases it's the entry most recently
531 * added, which makes this pretty quick.
533 * Thought: if it's not the most recent entry, just null it out. When we
534 * fill up, do a compaction pass before we expand the list.
536 static void deleteGlobalReference(jobject jobj) {
541 ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
542 if (!gDvm.jniGlobalRefTable.remove(IRT_FIRST_SEGMENT, jobj)) {
543 ALOGW("JNI: DeleteGlobalRef(%p) failed to find entry", jobj);
549 * Objects don't currently move, so we just need to create a reference
550 * that will ensure the array object isn't collected.
552 * We use a separate reference table, which is part of the GC root set.
554 static void pinPrimitiveArray(ArrayObject* arrayObj) {
555 if (arrayObj == NULL) {
559 ScopedPthreadMutexLock lock(&gDvm.jniPinRefLock);
561 if (!dvmAddToReferenceTable(&gDvm.jniPinRefTable, (Object*)arrayObj)) {
562 dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
563 ALOGE("Failed adding to JNI pinned array ref table (%d entries)",
564 (int) dvmReferenceTableEntries(&gDvm.jniPinRefTable));
569 * The total number of pinned primitive arrays should be pretty small.
570 * A single array should not be pinned more than once or twice; any
571 * more than that is a strong indicator that a Release function is
575 Object** ppObj = gDvm.jniPinRefTable.table;
576 while (ppObj < gDvm.jniPinRefTable.nextEntry) {
577 if (*ppObj++ == (Object*) arrayObj) {
582 if (count > kPinComplainThreshold) {
583 ALOGW("JNI: pin count on array %p (%s) is now %d",
584 arrayObj, arrayObj->clazz->descriptor, count);
590 * Un-pin the array object. If an object was pinned twice, it must be
591 * unpinned twice before it's free to move.
593 static void unpinPrimitiveArray(ArrayObject* arrayObj) {
594 if (arrayObj == NULL) {
598 ScopedPthreadMutexLock lock(&gDvm.jniPinRefLock);
599 if (!dvmRemoveFromReferenceTable(&gDvm.jniPinRefTable,
600 gDvm.jniPinRefTable.table, (Object*) arrayObj))
602 ALOGW("JNI: unpinPrimitiveArray(%p) failed to find entry (valid=%d)",
603 arrayObj, dvmIsHeapAddress((Object*) arrayObj));
609 * Dump the contents of the JNI reference tables to the log file.
611 * We only dump the local refs associated with the current thread.
613 void dvmDumpJniReferenceTables() {
614 Thread* self = dvmThreadSelf();
615 self->jniLocalRefTable.dump("JNI local");
616 gDvm.jniGlobalRefTable.dump("JNI global");
617 dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
620 void dvmDumpJniStats(DebugOutputTarget* target) {
621 dvmPrintDebugMessage(target, "JNI: CheckJNI is %s", gDvmJni.useCheckJni ? "on" : "off");
622 if (gDvmJni.forceCopy) {
623 dvmPrintDebugMessage(target, " (with forcecopy)");
625 dvmPrintDebugMessage(target, "; workarounds are %s", gDvmJni.workAroundAppJniBugs ? "on" : "off");
627 dvmLockMutex(&gDvm.jniPinRefLock);
628 dvmPrintDebugMessage(target, "; pins=%d", dvmReferenceTableEntries(&gDvm.jniPinRefTable));
629 dvmUnlockMutex(&gDvm.jniPinRefLock);
631 dvmLockMutex(&gDvm.jniGlobalRefLock);
632 dvmPrintDebugMessage(target, "; globals=%d", gDvm.jniGlobalRefTable.capacity());
633 dvmUnlockMutex(&gDvm.jniGlobalRefLock);
635 dvmLockMutex(&gDvm.jniWeakGlobalRefLock);
636 size_t weaks = gDvm.jniWeakGlobalRefTable.capacity();
638 dvmPrintDebugMessage(target, " (plus %d weak)", weaks);
640 dvmUnlockMutex(&gDvm.jniWeakGlobalRefLock);
642 dvmPrintDebugMessage(target, "\n\n");
646 * Verify that a reference passed in from native code is one that the
647 * code is allowed to have.
649 * It's okay for native code to pass us a reference that:
650 * - was passed in as an argument when invoked by native code (and hence
651 * is in the JNI local refs table)
652 * - was returned to it from JNI (and is now in the local refs table)
653 * - is present in the JNI global refs table
655 * Used by -Xcheck:jni and GetObjectRefType.
657 jobjectRefType dvmGetJNIRefType(Thread* self, jobject jobj) {
659 * IndirectRefKind is currently defined as an exact match of
660 * jobjectRefType, so this is easy. We have to decode it to determine
661 * if it's a valid reference and not merely valid-looking.
663 assert(jobj != NULL);
665 Object* obj = dvmDecodeIndirectRef(self, jobj);
666 if (obj == reinterpret_cast<Object*>(jobj) && gDvmJni.workAroundAppJniBugs) {
667 // If we're handing out direct pointers, check whether 'jobj' is a direct reference
668 // to a local reference.
669 return self->jniLocalRefTable.contains(obj) ? JNILocalRefType : JNIInvalidRefType;
670 } else if (obj == kInvalidIndirectRefObject) {
671 return JNIInvalidRefType;
673 return (jobjectRefType) indirectRefKind(jobj);
677 static void dumpMethods(Method* methods, size_t methodCount, const char* name) {
679 for (i = 0; i < methodCount; ++i) {
680 Method* method = &methods[i];
681 if (strcmp(name, method->name) == 0) {
682 char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
683 ALOGE("Candidate: %s.%s:%s", method->clazz->descriptor, name, desc);
689 static void dumpCandidateMethods(ClassObject* clazz, const char* methodName, const char* signature) {
690 ALOGE("ERROR: couldn't find native method");
691 ALOGE("Requested: %s.%s:%s", clazz->descriptor, methodName, signature);
692 dumpMethods(clazz->virtualMethods, clazz->virtualMethodCount, methodName);
693 dumpMethods(clazz->directMethods, clazz->directMethodCount, methodName);
697 * Register a method that uses JNI calling conventions.
699 static bool dvmRegisterJNIMethod(ClassObject* clazz, const char* methodName,
700 const char* signature, void* fnPtr)
706 // If a signature starts with a '!', we take that as a sign that the native code doesn't
707 // need the extra JNI arguments (the JNIEnv* and the jclass).
708 bool fastJni = false;
709 if (*signature == '!') {
712 ALOGV("fast JNI method %s.%s:%s detected", clazz->descriptor, methodName, signature);
715 Method* method = dvmFindDirectMethodByDescriptor(clazz, methodName, signature);
716 if (method == NULL) {
717 method = dvmFindVirtualMethodByDescriptor(clazz, methodName, signature);
719 if (method == NULL) {
720 dumpCandidateMethods(clazz, methodName, signature);
724 if (!dvmIsNativeMethod(method)) {
725 ALOGW("Unable to register: not native: %s.%s:%s", clazz->descriptor, methodName, signature);
730 // In this case, we have extra constraints to check...
731 if (dvmIsSynchronizedMethod(method)) {
732 // Synchronization is usually provided by the JNI bridge,
733 // but we won't have one.
734 ALOGE("fast JNI method %s.%s:%s cannot be synchronized",
735 clazz->descriptor, methodName, signature);
738 if (!dvmIsStaticMethod(method)) {
739 // There's no real reason for this constraint, but since we won't
740 // be supplying a JNIEnv* or a jobject 'this', you're effectively
741 // static anyway, so it seems clearer to say so.
742 ALOGE("fast JNI method %s.%s:%s cannot be non-static",
743 clazz->descriptor, methodName, signature);
748 if (method->nativeFunc != dvmResolveNativeMethod) {
749 /* this is allowed, but unusual */
750 ALOGV("Note: %s.%s:%s was already registered", clazz->descriptor, methodName, signature);
753 method->fastJni = fastJni;
754 dvmUseJNIBridge(method, fnPtr);
756 ALOGV("JNI-registered %s.%s:%s", clazz->descriptor, methodName, signature);
760 static const char* builtInPrefixes[] = {
763 "Lcom/google/android/",
768 "Lorg/apache/harmony/",
771 static bool shouldTrace(Method* method) {
772 const char* className = method->clazz->descriptor;
773 // Return true if the -Xjnitrace setting implies we should trace 'method'.
774 if (gDvm.jniTrace && strstr(className, gDvm.jniTrace)) {
777 // Return true if we're trying to log all third-party JNI activity and 'method' doesn't look
778 // like part of Android.
779 if (gDvmJni.logThirdPartyJni) {
780 for (size_t i = 0; i < NELEM(builtInPrefixes); ++i) {
781 if (strstr(className, builtInPrefixes[i]) == className) {
791 * Point "method->nativeFunc" at the JNI bridge, and overload "method->insns"
792 * to point at the actual function.
794 void dvmUseJNIBridge(Method* method, void* func) {
795 method->shouldTrace = shouldTrace(method);
797 // Does the method take any reference arguments?
798 method->noRef = true;
799 const char* cp = method->shorty;
800 while (*++cp != '\0') { // Pre-increment to skip return type.
802 method->noRef = false;
807 DalvikBridgeFunc bridge = gDvmJni.useCheckJni ? dvmCheckCallJNIMethod : dvmCallJNIMethod;
808 dvmSetNativeFunc(method, bridge, (const u2*) func);
811 // TODO: rewrite this to share code with CheckJNI's tracing...
812 static void appendValue(char type, const JValue value, char* buf, size_t n, bool appendComma)
814 size_t len = strlen(buf);
815 if (len >= n - 32) { // 32 should be longer than anything we could append.
824 if (value.b >= 0 && value.b < 10) {
825 sprintf(p, "%d", value.b);
827 sprintf(p, "%#x (%d)", value.b, value.b);
831 if (value.c < 0x7f && value.c >= ' ') {
832 sprintf(p, "U+%x ('%c')", value.c, value.c);
834 sprintf(p, "U+%x", value.c);
838 sprintf(p, "%g", value.d);
841 sprintf(p, "%g", value.f);
844 sprintf(p, "%d", value.i);
847 sprintf(p, "%#x", value.i);
850 sprintf(p, "%lld", value.j);
853 sprintf(p, "%d", value.s);
859 strcpy(p, value.z ? "true" : "false");
862 sprintf(p, "unknown type '%c'", type);
871 static void logNativeMethodEntry(const Method* method, const u4* args)
873 char thisString[32] = { 0 };
875 if (!dvmIsStaticMethod(method)) {
876 sprintf(thisString, "this=0x%08x ", *sp++);
879 char argsString[128]= { 0 };
880 const char* desc = &method->shorty[1];
881 while (*desc != '\0') {
882 char argType = *desc++;
884 if (argType == 'D' || argType == 'J') {
885 value.j = dvmGetArgLong(sp, 0);
890 appendValue(argType, value, argsString, sizeof(argsString),
894 std::string className(dvmHumanReadableDescriptor(method->clazz->descriptor));
895 char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
896 ALOGI("-> %s %s%s %s(%s)", className.c_str(), method->name, signature, thisString, argsString);
900 static void logNativeMethodExit(const Method* method, Thread* self, const JValue returnValue)
902 std::string className(dvmHumanReadableDescriptor(method->clazz->descriptor));
903 char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
904 if (dvmCheckException(self)) {
905 Object* exception = dvmGetException(self);
906 std::string exceptionClassName(dvmHumanReadableDescriptor(exception->clazz->descriptor));
907 ALOGI("<- %s %s%s threw %s", className.c_str(),
908 method->name, signature, exceptionClassName.c_str());
910 char returnValueString[128] = { 0 };
911 char returnType = method->shorty[0];
912 appendValue(returnType, returnValue, returnValueString, sizeof(returnValueString), false);
913 ALOGI("<- %s %s%s returned %s", className.c_str(),
914 method->name, signature, returnValueString);
920 * Get the method currently being executed by examining the interp stack.
922 const Method* dvmGetCurrentJNIMethod() {
923 assert(dvmThreadSelf() != NULL);
925 void* fp = dvmThreadSelf()->interpSave.curFrame;
926 const Method* meth = SAVEAREA_FROM_FP(fp)->method;
928 assert(meth != NULL);
929 assert(dvmIsNativeMethod(meth));
934 * Track a JNI MonitorEnter in the current thread.
936 * The goal is to be able to "implicitly" release all JNI-held monitors
937 * when the thread detaches.
939 * Monitors may be entered multiple times, so we add a new entry for each
940 * enter call. It would be more efficient to keep a counter. At present
941 * there's no real motivation to improve this however.
943 static void trackMonitorEnter(Thread* self, Object* obj) {
944 static const int kInitialSize = 16;
945 ReferenceTable* refTable = &self->jniMonitorRefTable;
947 /* init table on first use */
948 if (refTable->table == NULL) {
949 assert(refTable->maxEntries == 0);
951 if (!dvmInitReferenceTable(refTable, kInitialSize, INT_MAX)) {
952 ALOGE("Unable to initialize monitor tracking table");
957 if (!dvmAddToReferenceTable(refTable, obj)) {
958 /* ran out of memory? could throw exception instead */
959 ALOGE("Unable to add entry to monitor tracking table");
962 LOGVV("--- added monitor %p", obj);
967 * Track a JNI MonitorExit in the current thread.
969 static void trackMonitorExit(Thread* self, Object* obj) {
970 ReferenceTable* pRefTable = &self->jniMonitorRefTable;
972 if (!dvmRemoveFromReferenceTable(pRefTable, pRefTable->table, obj)) {
973 ALOGE("JNI monitor %p not found in tracking list", obj);
976 LOGVV("--- removed monitor %p", obj);
981 * Release all monitors held by the jniMonitorRefTable list.
983 void dvmReleaseJniMonitors(Thread* self) {
984 ReferenceTable* pRefTable = &self->jniMonitorRefTable;
985 Object** top = pRefTable->table;
990 Object** ptr = pRefTable->nextEntry;
991 while (--ptr >= top) {
992 if (!dvmUnlockObject(self, *ptr)) {
993 ALOGW("Unable to unlock monitor %p at thread detach", *ptr);
995 LOGVV("--- detach-releasing monitor %p", *ptr);
1000 pRefTable->nextEntry = pRefTable->table;
1004 * Determine if the specified class can be instantiated from JNI. This
1005 * is used by AllocObject / NewObject, which are documented as throwing
1006 * an exception for abstract and interface classes, and not accepting
1007 * array classes. We also want to reject attempts to create new Class
1008 * objects, since only DefineClass should do that.
1010 static bool canAllocClass(ClassObject* clazz) {
1011 if (dvmIsAbstractClass(clazz) || dvmIsInterfaceClass(clazz)) {
1012 /* JNI spec defines what this throws */
1013 dvmThrowInstantiationException(clazz, "abstract class or interface");
1015 } else if (dvmIsArrayClass(clazz) || dvmIsTheClassClass(clazz)) {
1016 /* spec says "must not" for arrays, ignores Class */
1017 dvmThrowInstantiationException(clazz, "wrong JNI function");
1025 * ===========================================================================
1027 * ===========================================================================
1031 * The functions here form a bridge between interpreted code and JNI native
1032 * functions. The basic task is to convert an array of primitives and
1033 * references into C-style function arguments. This is architecture-specific
1034 * and usually requires help from assembly code.
1036 * The bridge takes four arguments: the array of parameters, a place to
1037 * store the function result (if any), the method to call, and a pointer
1038 * to the current thread.
1040 * These functions aren't called directly from elsewhere in the VM.
1041 * A pointer in the Method struct points to one of these, and when a native
1042 * method is invoked the interpreter jumps to it.
1044 * (The "internal native" methods are invoked the same way, but instead
1045 * of calling through a bridge, the target method is called directly.)
1047 * The "args" array should not be modified, but we do so anyway for
1048 * performance reasons. We know that it points to the "outs" area on
1049 * the current method's interpreted stack. This area is ignored by the
1050 * precise GC, because there is no register map for a native method (for
1051 * an interpreted method the args would be listed in the argument set).
1052 * We know all of the values exist elsewhere on the interpreted stack,
1053 * because the method call setup copies them right before making the call,
1054 * so we don't have to worry about concealing stuff from the GC.
1056 * If we don't want to modify "args", we either have to create a local
1057 * copy and modify it before calling dvmPlatformInvoke, or we have to do
1058 * the local reference replacement within dvmPlatformInvoke. The latter
1059 * has some performance advantages, though if we can inline the local
1060 * reference adds we may win when there's a lot of reference args (unless
1061 * we want to code up some local ref table manipulation in assembly.
1065 * If necessary, convert the value in pResult from a local/global reference
1066 * to an object pointer.
1068 * If the returned reference is invalid, kInvalidIndirectRefObject will
1069 * be returned in pResult.
1071 static inline void convertReferenceResult(JNIEnv* env, JValue* pResult,
1072 const Method* method, Thread* self)
1074 if (method->shorty[0] == 'L' && !dvmCheckException(self) && pResult->l != NULL) {
1075 pResult->l = dvmDecodeIndirectRef(self, (jobject) pResult->l);
1080 * General form, handles all cases.
1082 void dvmCallJNIMethod(const u4* args, JValue* pResult, const Method* method, Thread* self) {
1083 u4* modArgs = (u4*) args;
1084 jclass staticMethodClass = NULL;
1086 u4 accessFlags = method->accessFlags;
1087 bool isSynchronized = (accessFlags & ACC_SYNCHRONIZED) != 0;
1089 //ALOGI("JNI calling %p (%s.%s:%s):", method->insns,
1090 // method->clazz->descriptor, method->name, method->shorty);
1093 * Walk the argument list, creating local references for appropriate
1098 if ((accessFlags & ACC_STATIC) != 0) {
1099 lockObj = (Object*) method->clazz;
1100 /* add the class object we pass in */
1101 staticMethodClass = (jclass) addLocalReference(self, (Object*) method->clazz);
1103 lockObj = (Object*) args[0];
1105 modArgs[idx++] = (u4) addLocalReference(self, (Object*) modArgs[0]);
1108 if (!method->noRef) {
1109 const char* shorty = &method->shorty[1]; /* skip return type */
1110 while (*shorty != '\0') {
1111 switch (*shorty++) {
1113 //ALOGI(" local %d: 0x%08x", idx, modArgs[idx]);
1114 if (modArgs[idx] != 0) {
1115 modArgs[idx] = (u4) addLocalReference(self, (Object*) modArgs[idx]);
1123 /* Z B C S I -- do nothing */
1130 if (UNLIKELY(method->shouldTrace)) {
1131 logNativeMethodEntry(method, args);
1133 if (UNLIKELY(isSynchronized)) {
1134 dvmLockObject(self, lockObj);
1137 ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
1139 ANDROID_MEMBAR_FULL(); /* guarantee ordering on method->insns */
1140 assert(method->insns != NULL);
1142 JNIEnv* env = self->jniEnv;
1143 COMPUTE_STACK_SUM(self);
1144 dvmPlatformInvoke(env,
1145 (ClassObject*) staticMethodClass,
1146 method->jniArgInfo, method->insSize, modArgs, method->shorty,
1147 (void*) method->insns, pResult);
1148 CHECK_STACK_SUM(self);
1150 dvmChangeStatus(self, oldStatus);
1152 convertReferenceResult(env, pResult, method, self);
1154 if (UNLIKELY(isSynchronized)) {
1155 dvmUnlockObject(self, lockObj);
1157 if (UNLIKELY(method->shouldTrace)) {
1158 logNativeMethodExit(method, self, *pResult);
1163 * ===========================================================================
1164 * JNI implementation
1165 * ===========================================================================
1169 * Return the version of the native method interface.
1171 static jint GetVersion(JNIEnv* env) {
1173 * There is absolutely no need to toggle the mode for correct behavior.
1174 * However, it does provide native code with a simple "suspend self
1175 * if necessary" call.
1177 ScopedJniThreadState ts(env);
1178 return JNI_VERSION_1_6;
1182 * Create a new class from a bag of bytes.
1184 * This is not currently supported within Dalvik.
1186 static jclass DefineClass(JNIEnv* env, const char *name, jobject loader,
1187 const jbyte* buf, jsize bufLen)
1189 UNUSED_PARAMETER(name);
1190 UNUSED_PARAMETER(loader);
1191 UNUSED_PARAMETER(buf);
1192 UNUSED_PARAMETER(bufLen);
1194 ScopedJniThreadState ts(env);
1195 ALOGW("JNI DefineClass is not supported");
1200 * Find a class by name.
1202 * We have to use the "no init" version of FindClass here, because we might
1203 * be getting the class prior to registering native methods that will be
1206 * We need to get the class loader associated with the current native
1207 * method. If there is no native method, e.g. we're calling this from native
1208 * code right after creating the VM, the spec says we need to use the class
1209 * loader returned by "ClassLoader.getBaseClassLoader". There is no such
1210 * method, but it's likely they meant ClassLoader.getSystemClassLoader.
1211 * We can't get that until after the VM has initialized though.
1213 static jclass FindClass(JNIEnv* env, const char* name) {
1214 ScopedJniThreadState ts(env);
1216 const Method* thisMethod = dvmGetCurrentJNIMethod();
1217 assert(thisMethod != NULL);
1220 Object* trackedLoader = NULL;
1221 if (ts.self()->classLoaderOverride != NULL) {
1222 /* hack for JNI_OnLoad */
1223 assert(strcmp(thisMethod->name, "nativeLoad") == 0);
1224 loader = ts.self()->classLoaderOverride;
1225 } else if (thisMethod == gDvm.methDalvikSystemNativeStart_main ||
1226 thisMethod == gDvm.methDalvikSystemNativeStart_run) {
1227 /* start point of invocation interface */
1228 if (!gDvm.initializing) {
1229 loader = trackedLoader = dvmGetSystemClassLoader();
1234 loader = thisMethod->clazz->classLoader;
1237 char* descriptor = dvmNameToDescriptor(name);
1238 if (descriptor == NULL) {
1241 ClassObject* clazz = dvmFindClassNoInit(descriptor, loader);
1244 jclass jclazz = (jclass) addLocalReference(ts.self(), (Object*) clazz);
1245 dvmReleaseTrackedAlloc(trackedLoader, ts.self());
1250 * Return the superclass of a class.
1252 static jclass GetSuperclass(JNIEnv* env, jclass jclazz) {
1253 ScopedJniThreadState ts(env);
1254 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1255 return (jclass) addLocalReference(ts.self(), (Object*)clazz->super);
1259 * Determine whether an object of clazz1 can be safely cast to clazz2.
1261 * Like IsInstanceOf, but with a pair of class objects instead of obj+class.
1263 static jboolean IsAssignableFrom(JNIEnv* env, jclass jclazz1, jclass jclazz2) {
1264 ScopedJniThreadState ts(env);
1265 ClassObject* clazz1 = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz1);
1266 ClassObject* clazz2 = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz2);
1267 return dvmInstanceof(clazz1, clazz2);
1271 * Given a java.lang.reflect.Method or .Constructor, return a methodID.
1273 static jmethodID FromReflectedMethod(JNIEnv* env, jobject jmethod) {
1274 ScopedJniThreadState ts(env);
1275 Object* method = dvmDecodeIndirectRef(ts.self(), jmethod);
1276 return (jmethodID) dvmGetMethodFromReflectObj(method);
1280 * Given a java.lang.reflect.Field, return a fieldID.
1282 static jfieldID FromReflectedField(JNIEnv* env, jobject jfield) {
1283 ScopedJniThreadState ts(env);
1284 Object* field = dvmDecodeIndirectRef(ts.self(), jfield);
1285 return (jfieldID) dvmGetFieldFromReflectObj(field);
1289 * Convert a methodID to a java.lang.reflect.Method or .Constructor.
1291 * (The "isStatic" field does not appear in the spec.)
1293 * Throws OutOfMemory and returns NULL on failure.
1295 static jobject ToReflectedMethod(JNIEnv* env, jclass jcls, jmethodID methodID, jboolean isStatic) {
1296 ScopedJniThreadState ts(env);
1297 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jcls);
1298 Object* obj = dvmCreateReflectObjForMethod(clazz, (Method*) methodID);
1299 dvmReleaseTrackedAlloc(obj, NULL);
1300 return addLocalReference(ts.self(), obj);
1304 * Convert a fieldID to a java.lang.reflect.Field.
1306 * (The "isStatic" field does not appear in the spec.)
1308 * Throws OutOfMemory and returns NULL on failure.
1310 static jobject ToReflectedField(JNIEnv* env, jclass jcls, jfieldID fieldID, jboolean isStatic) {
1311 ScopedJniThreadState ts(env);
1312 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jcls);
1313 Object* obj = dvmCreateReflectObjForField(clazz, (Field*) fieldID);
1314 dvmReleaseTrackedAlloc(obj, NULL);
1315 return addLocalReference(ts.self(), obj);
1319 * Take this exception and throw it.
1321 static jint Throw(JNIEnv* env, jthrowable jobj) {
1322 ScopedJniThreadState ts(env);
1324 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1325 dvmSetException(ts.self(), obj);
1332 * Constructs an exception object from the specified class with the message
1333 * specified by "message", and throws it.
1335 static jint ThrowNew(JNIEnv* env, jclass jclazz, const char* message) {
1336 ScopedJniThreadState ts(env);
1337 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1338 dvmThrowException(clazz, message);
1339 // TODO: should return failure if this didn't work (e.g. OOM)
1344 * If an exception is being thrown, return the exception object. Otherwise,
1347 * TODO: if there is no pending exception, we should be able to skip the
1348 * enter/exit checks. If we find one, we need to enter and then re-fetch
1349 * the exception (in case it got moved by a compacting GC).
1351 static jthrowable ExceptionOccurred(JNIEnv* env) {
1352 ScopedJniThreadState ts(env);
1353 Object* exception = dvmGetException(ts.self());
1354 jthrowable localException = (jthrowable) addLocalReference(ts.self(), exception);
1355 if (localException == NULL && exception != NULL) {
1357 * We were unable to add a new local reference, and threw a new
1358 * exception. We can't return "exception", because it's not a
1359 * local reference. So we have to return NULL, indicating that
1360 * there was no exception, even though it's pretty much raining
1361 * exceptions in here.
1363 ALOGW("JNI WARNING: addLocal/exception combo");
1365 return localException;
1369 * Print an exception and stack trace to stderr.
1371 static void ExceptionDescribe(JNIEnv* env) {
1372 ScopedJniThreadState ts(env);
1373 Object* exception = dvmGetException(ts.self());
1374 if (exception != NULL) {
1375 dvmPrintExceptionStackTrace();
1377 ALOGI("Odd: ExceptionDescribe called, but no exception pending");
1382 * Clear the exception currently being thrown.
1384 * TODO: we should be able to skip the enter/exit stuff.
1386 static void ExceptionClear(JNIEnv* env) {
1387 ScopedJniThreadState ts(env);
1388 dvmClearException(ts.self());
1392 * Kill the VM. This function does not return.
1394 static void FatalError(JNIEnv* env, const char* msg) {
1395 //dvmChangeStatus(NULL, THREAD_RUNNING);
1396 ALOGE("JNI posting fatal error: %s", msg);
1401 * Push a new JNI frame on the stack, with a new set of locals.
1403 * The new frame must have the same method pointer. (If for no other
1404 * reason than FindClass needs it to get the appropriate class loader.)
1406 static jint PushLocalFrame(JNIEnv* env, jint capacity) {
1407 ScopedJniThreadState ts(env);
1408 if (!ensureLocalCapacity(ts.self(), capacity) ||
1409 !dvmPushLocalFrame(ts.self(), dvmGetCurrentJNIMethod()))
1411 /* yes, OutOfMemoryError, not StackOverflowError */
1412 dvmClearException(ts.self());
1413 dvmThrowOutOfMemoryError("out of stack in JNI PushLocalFrame");
1420 * Pop the local frame off. If "jresult" is not null, add it as a
1421 * local reference on the now-current frame.
1423 static jobject PopLocalFrame(JNIEnv* env, jobject jresult) {
1424 ScopedJniThreadState ts(env);
1425 Object* result = dvmDecodeIndirectRef(ts.self(), jresult);
1426 if (!dvmPopLocalFrame(ts.self())) {
1427 ALOGW("JNI WARNING: too many PopLocalFrame calls");
1428 dvmClearException(ts.self());
1429 dvmThrowRuntimeException("too many PopLocalFrame calls");
1431 return addLocalReference(ts.self(), result);
1435 * Add a reference to the global list.
1437 static jobject NewGlobalRef(JNIEnv* env, jobject jobj) {
1438 ScopedJniThreadState ts(env);
1439 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1440 return addGlobalReference(obj);
1444 * Delete a reference from the global list.
1446 static void DeleteGlobalRef(JNIEnv* env, jobject jglobalRef) {
1447 ScopedJniThreadState ts(env);
1448 deleteGlobalReference(jglobalRef);
1453 * Add a reference to the local list.
1455 static jobject NewLocalRef(JNIEnv* env, jobject jobj) {
1456 ScopedJniThreadState ts(env);
1457 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1458 return addLocalReference(ts.self(), obj);
1462 * Delete a reference from the local list.
1464 static void DeleteLocalRef(JNIEnv* env, jobject jlocalRef) {
1465 ScopedJniThreadState ts(env);
1466 deleteLocalReference(ts.self(), jlocalRef);
1470 * Ensure that the local references table can hold at least this many
1473 static jint EnsureLocalCapacity(JNIEnv* env, jint capacity) {
1474 ScopedJniThreadState ts(env);
1475 bool okay = ensureLocalCapacity(ts.self(), capacity);
1477 dvmThrowOutOfMemoryError("can't ensure local reference capacity");
1479 return okay ? 0 : -1;
1484 * Determine whether two Object references refer to the same underlying object.
1486 static jboolean IsSameObject(JNIEnv* env, jobject jref1, jobject jref2) {
1487 ScopedJniThreadState ts(env);
1488 Object* obj1 = dvmDecodeIndirectRef(ts.self(), jref1);
1489 Object* obj2 = dvmDecodeIndirectRef(ts.self(), jref2);
1490 return (obj1 == obj2);
1494 * Allocate a new object without invoking any constructors.
1496 static jobject AllocObject(JNIEnv* env, jclass jclazz) {
1497 ScopedJniThreadState ts(env);
1499 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1500 if (!canAllocClass(clazz) ||
1501 (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)))
1503 assert(dvmCheckException(ts.self()));
1507 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1508 return addLocalReference(ts.self(), newObj);
1512 * Allocate a new object and invoke the supplied constructor.
1514 static jobject NewObject(JNIEnv* env, jclass jclazz, jmethodID methodID, ...) {
1515 ScopedJniThreadState ts(env);
1516 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1518 if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
1519 assert(dvmCheckException(ts.self()));
1523 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1524 jobject result = addLocalReference(ts.self(), newObj);
1525 if (newObj != NULL) {
1528 va_start(args, methodID);
1529 dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args);
1535 static jobject NewObjectV(JNIEnv* env, jclass jclazz, jmethodID methodID, va_list args) {
1536 ScopedJniThreadState ts(env);
1537 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1539 if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
1540 assert(dvmCheckException(ts.self()));
1544 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1545 jobject result = addLocalReference(ts.self(), newObj);
1546 if (newObj != NULL) {
1548 dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args);
1553 static jobject NewObjectA(JNIEnv* env, jclass jclazz, jmethodID methodID, jvalue* args) {
1554 ScopedJniThreadState ts(env);
1555 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1557 if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
1558 assert(dvmCheckException(ts.self()));
1562 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1563 jobject result = addLocalReference(ts.self(), newObj);
1564 if (newObj != NULL) {
1566 dvmCallMethodA(ts.self(), (Method*) methodID, newObj, true, &unused, args);
1572 * Returns the class of an object.
1574 * JNI spec says: obj must not be NULL.
1576 static jclass GetObjectClass(JNIEnv* env, jobject jobj) {
1577 ScopedJniThreadState ts(env);
1579 assert(jobj != NULL);
1581 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1582 return (jclass) addLocalReference(ts.self(), (Object*) obj->clazz);
1586 * Determine whether "obj" is an instance of "clazz".
1588 static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass jclazz) {
1589 ScopedJniThreadState ts(env);
1591 assert(jclazz != NULL);
1596 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1597 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1598 return dvmInstanceof(obj->clazz, clazz);
1602 * Get a method ID for an instance method.
1604 * While Dalvik bytecode has distinct instructions for virtual, super,
1605 * static, direct, and interface method invocation, JNI only provides
1606 * two functions for acquiring a method ID. This call handles everything
1607 * but static methods.
1609 * JNI defines <init> as an instance method, but Dalvik considers it a
1610 * "direct" method, so we have to special-case it here.
1612 * Dalvik also puts all private methods into the "direct" list, so we
1613 * really need to just search both lists.
1615 static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1616 ScopedJniThreadState ts(env);
1618 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1619 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1620 assert(dvmCheckException(ts.self()));
1621 } else if (dvmIsInterfaceClass(clazz)) {
1622 Method* meth = dvmFindInterfaceMethodHierByDescriptor(clazz, name, sig);
1624 dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
1625 "no method with name='%s' signature='%s' in interface %s",
1626 name, sig, clazz->descriptor);
1628 return (jmethodID) meth;
1630 Method* meth = dvmFindVirtualMethodHierByDescriptor(clazz, name, sig);
1632 /* search private methods and constructors; non-hierarchical */
1633 meth = dvmFindDirectMethodByDescriptor(clazz, name, sig);
1635 if (meth != NULL && dvmIsStaticMethod(meth)) {
1637 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
1638 ALOGD("GetMethodID: not returning static method %s.%s %s",
1639 clazz->descriptor, meth->name, desc);
1645 dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
1646 "no method with name='%s' signature='%s' in class %s",
1647 name, sig, clazz->descriptor);
1650 * The method's class may not be the same as clazz, but if
1651 * it isn't this must be a virtual method and the class must
1652 * be a superclass (and, hence, already initialized).
1654 assert(dvmIsClassInitialized(meth->clazz) || dvmIsClassInitializing(meth->clazz));
1656 return (jmethodID) meth;
1660 * Get a field ID (instance fields).
1662 static jfieldID GetFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1663 ScopedJniThreadState ts(env);
1665 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1667 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1668 assert(dvmCheckException(ts.self()));
1672 jfieldID id = (jfieldID) dvmFindInstanceFieldHier(clazz, name, sig);
1674 dvmThrowExceptionFmt(gDvm.exNoSuchFieldError,
1675 "no field with name='%s' signature='%s' in class %s",
1676 name, sig, clazz->descriptor);
1682 * Get the method ID for a static method in a class.
1684 static jmethodID GetStaticMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1685 ScopedJniThreadState ts(env);
1687 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1688 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1689 assert(dvmCheckException(ts.self()));
1693 Method* meth = dvmFindDirectMethodHierByDescriptor(clazz, name, sig);
1695 /* make sure it's static, not virtual+private */
1696 if (meth != NULL && !dvmIsStaticMethod(meth)) {
1698 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
1699 ALOGD("GetStaticMethodID: not returning nonstatic method %s.%s %s",
1700 clazz->descriptor, meth->name, desc);
1706 jmethodID id = (jmethodID) meth;
1708 dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
1709 "no static method with name='%s' signature='%s' in class %s",
1710 name, sig, clazz->descriptor);
1716 * Get a field ID (static fields).
1718 static jfieldID GetStaticFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1719 ScopedJniThreadState ts(env);
1721 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1722 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1723 assert(dvmCheckException(ts.self()));
1727 jfieldID id = (jfieldID) dvmFindStaticFieldHier(clazz, name, sig);
1729 dvmThrowExceptionFmt(gDvm.exNoSuchFieldError,
1730 "no static field with name='%s' signature='%s' in class %s",
1731 name, sig, clazz->descriptor);
1737 * Get a static field.
1739 * If we get an object reference, add it to the local refs list.
1741 #define GET_STATIC_TYPE_FIELD(_ctype, _jname, _isref) \
1742 static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass jclazz, \
1745 UNUSED_PARAMETER(jclazz); \
1746 ScopedJniThreadState ts(env); \
1747 StaticField* sfield = (StaticField*) fieldID; \
1749 if (dvmIsVolatileField(sfield)) { \
1750 if (_isref) { /* only when _ctype==jobject */ \
1751 Object* obj = dvmGetStaticFieldObjectVolatile(sfield); \
1752 value = (_ctype)(u4)addLocalReference(ts.self(), obj); \
1754 value = (_ctype) dvmGetStaticField##_jname##Volatile(sfield);\
1758 Object* obj = dvmGetStaticFieldObject(sfield); \
1759 value = (_ctype)(u4)addLocalReference(ts.self(), obj); \
1761 value = (_ctype) dvmGetStaticField##_jname(sfield); \
1766 GET_STATIC_TYPE_FIELD(jobject, Object, true);
1767 GET_STATIC_TYPE_FIELD(jboolean, Boolean, false);
1768 GET_STATIC_TYPE_FIELD(jbyte, Byte, false);
1769 GET_STATIC_TYPE_FIELD(jchar, Char, false);
1770 GET_STATIC_TYPE_FIELD(jshort, Short, false);
1771 GET_STATIC_TYPE_FIELD(jint, Int, false);
1772 GET_STATIC_TYPE_FIELD(jlong, Long, false);
1773 GET_STATIC_TYPE_FIELD(jfloat, Float, false);
1774 GET_STATIC_TYPE_FIELD(jdouble, Double, false);
1777 * Set a static field.
1779 #define SET_STATIC_TYPE_FIELD(_ctype, _ctype2, _jname, _isref) \
1780 static void SetStatic##_jname##Field(JNIEnv* env, jclass jclazz, \
1781 jfieldID fieldID, _ctype value) \
1783 UNUSED_PARAMETER(jclazz); \
1784 ScopedJniThreadState ts(env); \
1785 StaticField* sfield = (StaticField*) fieldID; \
1786 if (dvmIsVolatileField(sfield)) { \
1787 if (_isref) { /* only when _ctype==jobject */ \
1788 Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1789 dvmSetStaticFieldObjectVolatile(sfield, valObj); \
1791 dvmSetStaticField##_jname##Volatile(sfield, (_ctype2)value);\
1795 Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1796 dvmSetStaticFieldObject(sfield, valObj); \
1798 dvmSetStaticField##_jname(sfield, (_ctype2)value); \
1802 SET_STATIC_TYPE_FIELD(jobject, Object*, Object, true);
1803 SET_STATIC_TYPE_FIELD(jboolean, bool, Boolean, false);
1804 SET_STATIC_TYPE_FIELD(jbyte, s1, Byte, false);
1805 SET_STATIC_TYPE_FIELD(jchar, u2, Char, false);
1806 SET_STATIC_TYPE_FIELD(jshort, s2, Short, false);
1807 SET_STATIC_TYPE_FIELD(jint, s4, Int, false);
1808 SET_STATIC_TYPE_FIELD(jlong, s8, Long, false);
1809 SET_STATIC_TYPE_FIELD(jfloat, float, Float, false);
1810 SET_STATIC_TYPE_FIELD(jdouble, double, Double, false);
1813 * Get an instance field.
1815 * If we get an object reference, add it to the local refs list.
1817 #define GET_TYPE_FIELD(_ctype, _jname, _isref) \
1818 static _ctype Get##_jname##Field(JNIEnv* env, jobject jobj, \
1821 ScopedJniThreadState ts(env); \
1822 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1823 InstField* field = (InstField*) fieldID; \
1825 if (dvmIsVolatileField(field)) { \
1826 if (_isref) { /* only when _ctype==jobject */ \
1828 dvmGetFieldObjectVolatile(obj, field->byteOffset); \
1829 value = (_ctype)(u4)addLocalReference(ts.self(), valObj); \
1832 dvmGetField##_jname##Volatile(obj, field->byteOffset); \
1836 Object* valObj = dvmGetFieldObject(obj, field->byteOffset); \
1837 value = (_ctype)(u4)addLocalReference(ts.self(), valObj); \
1839 value = (_ctype) dvmGetField##_jname(obj, field->byteOffset);\
1844 GET_TYPE_FIELD(jobject, Object, true);
1845 GET_TYPE_FIELD(jboolean, Boolean, false);
1846 GET_TYPE_FIELD(jbyte, Byte, false);
1847 GET_TYPE_FIELD(jchar, Char, false);
1848 GET_TYPE_FIELD(jshort, Short, false);
1849 GET_TYPE_FIELD(jint, Int, false);
1850 GET_TYPE_FIELD(jlong, Long, false);
1851 GET_TYPE_FIELD(jfloat, Float, false);
1852 GET_TYPE_FIELD(jdouble, Double, false);
1855 * Set an instance field.
1857 #define SET_TYPE_FIELD(_ctype, _ctype2, _jname, _isref) \
1858 static void Set##_jname##Field(JNIEnv* env, jobject jobj, \
1859 jfieldID fieldID, _ctype value) \
1861 ScopedJniThreadState ts(env); \
1862 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1863 InstField* field = (InstField*) fieldID; \
1864 if (dvmIsVolatileField(field)) { \
1865 if (_isref) { /* only when _ctype==jobject */ \
1866 Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1867 dvmSetFieldObjectVolatile(obj, field->byteOffset, valObj); \
1869 dvmSetField##_jname##Volatile(obj, \
1870 field->byteOffset, (_ctype2)value); \
1874 Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1875 dvmSetFieldObject(obj, field->byteOffset, valObj); \
1877 dvmSetField##_jname(obj, \
1878 field->byteOffset, (_ctype2)value); \
1882 SET_TYPE_FIELD(jobject, Object*, Object, true);
1883 SET_TYPE_FIELD(jboolean, bool, Boolean, false);
1884 SET_TYPE_FIELD(jbyte, s1, Byte, false);
1885 SET_TYPE_FIELD(jchar, u2, Char, false);
1886 SET_TYPE_FIELD(jshort, s2, Short, false);
1887 SET_TYPE_FIELD(jint, s4, Int, false);
1888 SET_TYPE_FIELD(jlong, s8, Long, false);
1889 SET_TYPE_FIELD(jfloat, float, Float, false);
1890 SET_TYPE_FIELD(jdouble, double, Double, false);
1893 * Make a virtual method call.
1895 * Three versions (..., va_list, jvalue[]) for each return type. If we're
1896 * returning an Object, we have to add it to the local references table.
1898 #define CALL_VIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \
1899 static _ctype Call##_jname##Method(JNIEnv* env, jobject jobj, \
1900 jmethodID methodID, ...) \
1902 ScopedJniThreadState ts(env); \
1903 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1904 const Method* meth; \
1907 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
1908 if (meth == NULL) { \
1911 va_start(args, methodID); \
1912 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \
1914 if (_isref && !dvmCheckException(ts.self())) \
1915 result.l = (Object*)addLocalReference(ts.self(), result.l); \
1918 static _ctype Call##_jname##MethodV(JNIEnv* env, jobject jobj, \
1919 jmethodID methodID, va_list args) \
1921 ScopedJniThreadState ts(env); \
1922 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1923 const Method* meth; \
1925 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
1926 if (meth == NULL) { \
1929 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \
1930 if (_isref && !dvmCheckException(ts.self())) \
1931 result.l = (Object*)addLocalReference(ts.self(), result.l); \
1934 static _ctype Call##_jname##MethodA(JNIEnv* env, jobject jobj, \
1935 jmethodID methodID, jvalue* args) \
1937 ScopedJniThreadState ts(env); \
1938 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1939 const Method* meth; \
1941 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
1942 if (meth == NULL) { \
1945 dvmCallMethodA(ts.self(), meth, obj, true, &result, args); \
1946 if (_isref && !dvmCheckException(ts.self())) \
1947 result.l = (Object*)addLocalReference(ts.self(), result.l); \
1950 CALL_VIRTUAL(jobject, Object, NULL, (jobject) result.l, true);
1951 CALL_VIRTUAL(jboolean, Boolean, 0, result.z, false);
1952 CALL_VIRTUAL(jbyte, Byte, 0, result.b, false);
1953 CALL_VIRTUAL(jchar, Char, 0, result.c, false);
1954 CALL_VIRTUAL(jshort, Short, 0, result.s, false);
1955 CALL_VIRTUAL(jint, Int, 0, result.i, false);
1956 CALL_VIRTUAL(jlong, Long, 0, result.j, false);
1957 CALL_VIRTUAL(jfloat, Float, 0.0f, result.f, false);
1958 CALL_VIRTUAL(jdouble, Double, 0.0, result.d, false);
1959 CALL_VIRTUAL(void, Void, , , false);
1962 * Make a "non-virtual" method call. We're still calling a virtual method,
1963 * but this time we're not doing an indirection through the object's vtable.
1964 * The "clazz" parameter defines which implementation of a method we want.
1966 * Three versions (..., va_list, jvalue[]) for each return type.
1968 #define CALL_NONVIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \
1969 static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, jobject jobj, \
1970 jclass jclazz, jmethodID methodID, ...) \
1972 ScopedJniThreadState ts(env); \
1973 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1974 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz); \
1975 const Method* meth; \
1978 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
1979 if (meth == NULL) { \
1982 va_start(args, methodID); \
1983 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \
1984 if (_isref && !dvmCheckException(ts.self())) \
1985 result.l = (Object*)addLocalReference(ts.self(), result.l); \
1989 static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, jobject jobj,\
1990 jclass jclazz, jmethodID methodID, va_list args) \
1992 ScopedJniThreadState ts(env); \
1993 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1994 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz); \
1995 const Method* meth; \
1997 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
1998 if (meth == NULL) { \
2001 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \
2002 if (_isref && !dvmCheckException(ts.self())) \
2003 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2006 static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, jobject jobj,\
2007 jclass jclazz, jmethodID methodID, jvalue* args) \
2009 ScopedJniThreadState ts(env); \
2010 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
2011 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz); \
2012 const Method* meth; \
2014 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
2015 if (meth == NULL) { \
2018 dvmCallMethodA(ts.self(), meth, obj, true, &result, args); \
2019 if (_isref && !dvmCheckException(ts.self())) \
2020 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2023 CALL_NONVIRTUAL(jobject, Object, NULL, (jobject) result.l, true);
2024 CALL_NONVIRTUAL(jboolean, Boolean, 0, result.z, false);
2025 CALL_NONVIRTUAL(jbyte, Byte, 0, result.b, false);
2026 CALL_NONVIRTUAL(jchar, Char, 0, result.c, false);
2027 CALL_NONVIRTUAL(jshort, Short, 0, result.s, false);
2028 CALL_NONVIRTUAL(jint, Int, 0, result.i, false);
2029 CALL_NONVIRTUAL(jlong, Long, 0, result.j, false);
2030 CALL_NONVIRTUAL(jfloat, Float, 0.0f, result.f, false);
2031 CALL_NONVIRTUAL(jdouble, Double, 0.0, result.d, false);
2032 CALL_NONVIRTUAL(void, Void, , , false);
2036 * Call a static method.
2038 #define CALL_STATIC(_ctype, _jname, _retfail, _retok, _isref) \
2039 static _ctype CallStatic##_jname##Method(JNIEnv* env, jclass jclazz, \
2040 jmethodID methodID, ...) \
2042 UNUSED_PARAMETER(jclazz); \
2043 ScopedJniThreadState ts(env); \
2046 va_start(args, methodID); \
2047 dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
2049 if (_isref && !dvmCheckException(ts.self())) \
2050 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2053 static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass jclazz, \
2054 jmethodID methodID, va_list args) \
2056 UNUSED_PARAMETER(jclazz); \
2057 ScopedJniThreadState ts(env); \
2059 dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
2060 if (_isref && !dvmCheckException(ts.self())) \
2061 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2064 static _ctype CallStatic##_jname##MethodA(JNIEnv* env, jclass jclazz, \
2065 jmethodID methodID, jvalue* args) \
2067 UNUSED_PARAMETER(jclazz); \
2068 ScopedJniThreadState ts(env); \
2070 dvmCallMethodA(ts.self(), (Method*)methodID, NULL, true, &result, args);\
2071 if (_isref && !dvmCheckException(ts.self())) \
2072 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2075 CALL_STATIC(jobject, Object, NULL, (jobject) result.l, true);
2076 CALL_STATIC(jboolean, Boolean, 0, result.z, false);
2077 CALL_STATIC(jbyte, Byte, 0, result.b, false);
2078 CALL_STATIC(jchar, Char, 0, result.c, false);
2079 CALL_STATIC(jshort, Short, 0, result.s, false);
2080 CALL_STATIC(jint, Int, 0, result.i, false);
2081 CALL_STATIC(jlong, Long, 0, result.j, false);
2082 CALL_STATIC(jfloat, Float, 0.0f, result.f, false);
2083 CALL_STATIC(jdouble, Double, 0.0, result.d, false);
2084 CALL_STATIC(void, Void, , , false);
2087 * Create a new String from Unicode data.
2089 * If "len" is zero, we will return an empty string even if "unicodeChars"
2090 * is NULL. (The JNI spec is vague here.)
2092 static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) {
2093 ScopedJniThreadState ts(env);
2094 StringObject* jstr = dvmCreateStringFromUnicode(unicodeChars, len);
2098 dvmReleaseTrackedAlloc((Object*) jstr, NULL);
2099 return (jstring) addLocalReference(ts.self(), (Object*) jstr);
2103 * Return the length of a String in Unicode character units.
2105 static jsize GetStringLength(JNIEnv* env, jstring jstr) {
2106 ScopedJniThreadState ts(env);
2107 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2108 return strObj->length();
2113 * Get a string's character data.
2115 * The result is guaranteed to be valid until ReleaseStringChars is
2116 * called, which means we have to pin it or return a copy.
2118 static const jchar* GetStringChars(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2119 ScopedJniThreadState ts(env);
2121 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2122 ArrayObject* strChars = strObj->array();
2124 pinPrimitiveArray(strChars);
2126 const u2* data = strObj->chars();
2127 if (isCopy != NULL) {
2128 *isCopy = JNI_FALSE;
2130 return (jchar*) data;
2134 * Release our grip on some characters from a string.
2136 static void ReleaseStringChars(JNIEnv* env, jstring jstr, const jchar* chars) {
2137 ScopedJniThreadState ts(env);
2138 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2139 ArrayObject* strChars = strObj->array();
2140 unpinPrimitiveArray(strChars);
2144 * Create a new java.lang.String object from chars in modified UTF-8 form.
2146 * The spec doesn't say how to handle a NULL string. Popular desktop VMs
2147 * accept it and return a NULL pointer in response.
2149 static jstring NewStringUTF(JNIEnv* env, const char* bytes) {
2150 ScopedJniThreadState ts(env);
2151 if (bytes == NULL) {
2154 /* note newStr could come back NULL on OOM */
2155 StringObject* newStr = dvmCreateStringFromCstr(bytes);
2156 jstring result = (jstring) addLocalReference(ts.self(), (Object*) newStr);
2157 dvmReleaseTrackedAlloc((Object*)newStr, NULL);
2162 * Return the length in bytes of the modified UTF-8 form of the string.
2164 static jsize GetStringUTFLength(JNIEnv* env, jstring jstr) {
2165 ScopedJniThreadState ts(env);
2166 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2167 if (strObj == NULL) {
2168 return 0; // Should we throw something or assert?
2170 return strObj->utfLength();
2174 * Convert "string" to modified UTF-8 and return a pointer. The returned
2175 * value must be released with ReleaseStringUTFChars.
2177 * According to the JNI reference, "Returns a pointer to a UTF-8 string,
2178 * or NULL if the operation fails. Returns NULL if and only if an invocation
2179 * of this function has thrown an exception."
2181 * The behavior here currently follows that of other open-source VMs, which
2182 * quietly return NULL if "string" is NULL. We should consider throwing an
2183 * NPE. (The CheckJNI code blows up if you try to pass in a NULL string,
2184 * which should catch this sort of thing during development.) Certain other
2185 * VMs will crash with a segmentation fault.
2187 static const char* GetStringUTFChars(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2188 ScopedJniThreadState ts(env);
2190 /* this shouldn't happen; throw NPE? */
2193 if (isCopy != NULL) {
2196 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2197 char* newStr = dvmCreateCstrFromString(strObj);
2198 if (newStr == NULL) {
2199 /* assume memory failure */
2200 dvmThrowOutOfMemoryError("native heap string alloc failed");
2206 * Release a string created by GetStringUTFChars().
2208 static void ReleaseStringUTFChars(JNIEnv* env, jstring jstr, const char* utf) {
2209 ScopedJniThreadState ts(env);
2214 * Return the capacity of the array.
2216 static jsize GetArrayLength(JNIEnv* env, jarray jarr) {
2217 ScopedJniThreadState ts(env);
2218 ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2219 return arrObj->length;
2223 * Construct a new array that holds objects from class "elementClass".
2225 static jobjectArray NewObjectArray(JNIEnv* env, jsize length,
2226 jclass jelementClass, jobject jinitialElement)
2228 ScopedJniThreadState ts(env);
2230 if (jelementClass == NULL) {
2231 dvmThrowNullPointerException("JNI NewObjectArray elementClass == NULL");
2235 ClassObject* elemClassObj = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jelementClass);
2236 ClassObject* arrayClass = dvmFindArrayClassForElement(elemClassObj);
2237 ArrayObject* newObj = dvmAllocArrayByClass(arrayClass, length, ALLOC_DEFAULT);
2238 if (newObj == NULL) {
2239 assert(dvmCheckException(ts.self()));
2242 jobjectArray newArray = (jobjectArray) addLocalReference(ts.self(), (Object*) newObj);
2243 dvmReleaseTrackedAlloc((Object*) newObj, NULL);
2246 * Initialize the array.
2248 if (jinitialElement != NULL) {
2249 Object* initialElement = dvmDecodeIndirectRef(ts.self(), jinitialElement);
2250 Object** arrayData = (Object**) (void*) newObj->contents;
2251 for (jsize i = 0; i < length; ++i) {
2252 arrayData[i] = initialElement;
2259 static bool checkArrayElementBounds(ArrayObject* arrayObj, jsize index) {
2260 assert(arrayObj != NULL);
2261 if (index < 0 || index >= (int) arrayObj->length) {
2262 dvmThrowArrayIndexOutOfBoundsException(arrayObj->length, index);
2269 * Get one element of an Object array.
2271 * Add the object to the local references table in case the array goes away.
2273 static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index) {
2274 ScopedJniThreadState ts(env);
2276 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2277 if (!checkArrayElementBounds(arrayObj, index)) {
2281 Object* value = ((Object**) (void*) arrayObj->contents)[index];
2282 return addLocalReference(ts.self(), value);
2286 * Set one element of an Object array.
2288 static void SetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index, jobject jobj) {
2289 ScopedJniThreadState ts(env);
2291 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2292 if (!checkArrayElementBounds(arrayObj, index)) {
2296 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
2298 if (obj != NULL && !dvmCanPutArrayElement(obj->clazz, arrayObj->clazz)) {
2299 ALOGV("Can't put a '%s'(%p) into array type='%s'(%p)",
2300 obj->clazz->descriptor, obj,
2301 arrayObj->clazz->descriptor, arrayObj);
2302 dvmThrowArrayStoreExceptionIncompatibleElement(obj->clazz, arrayObj->clazz);
2306 //ALOGV("JNI: set element %d in array %p to %p", index, array, value);
2308 dvmSetObjectArrayElement(arrayObj, index, obj);
2312 * Create a new array of primitive elements.
2314 #define NEW_PRIMITIVE_ARRAY(_artype, _jname, _typechar) \
2315 static _artype New##_jname##Array(JNIEnv* env, jsize length) { \
2316 ScopedJniThreadState ts(env); \
2317 ArrayObject* arrayObj = dvmAllocPrimitiveArray(_typechar, length, ALLOC_DEFAULT); \
2318 if (arrayObj == NULL) { \
2321 _artype result = (_artype) addLocalReference(ts.self(), (Object*) arrayObj); \
2322 dvmReleaseTrackedAlloc((Object*) arrayObj, NULL); \
2325 NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean, 'Z');
2326 NEW_PRIMITIVE_ARRAY(jbyteArray, Byte, 'B');
2327 NEW_PRIMITIVE_ARRAY(jcharArray, Char, 'C');
2328 NEW_PRIMITIVE_ARRAY(jshortArray, Short, 'S');
2329 NEW_PRIMITIVE_ARRAY(jintArray, Int, 'I');
2330 NEW_PRIMITIVE_ARRAY(jlongArray, Long, 'J');
2331 NEW_PRIMITIVE_ARRAY(jfloatArray, Float, 'F');
2332 NEW_PRIMITIVE_ARRAY(jdoubleArray, Double, 'D');
2335 * Get a pointer to a C array of primitive elements from an array object
2336 * of the matching type.
2338 * In a compacting GC, we either need to return a copy of the elements or
2339 * "pin" the memory. Otherwise we run the risk of native code using the
2340 * buffer as the destination of e.g. a blocking read() call that wakes up
2343 #define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
2344 static _ctype* Get##_jname##ArrayElements(JNIEnv* env, \
2345 _ctype##Array jarr, jboolean* isCopy) \
2347 ScopedJniThreadState ts(env); \
2348 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2349 pinPrimitiveArray(arrayObj); \
2350 _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2351 if (isCopy != NULL) { \
2352 *isCopy = JNI_FALSE; \
2358 * Release the storage locked down by the "get" function.
2360 * The spec says, "'mode' has no effect if 'elems' is not a copy of the
2361 * elements in 'array'." They apparently did not anticipate the need to
2364 #define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
2365 static void Release##_jname##ArrayElements(JNIEnv* env, \
2366 _ctype##Array jarr, _ctype* elems, jint mode) \
2368 UNUSED_PARAMETER(elems); \
2369 if (mode != JNI_COMMIT) { \
2370 ScopedJniThreadState ts(env); \
2371 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2372 unpinPrimitiveArray(arrayObj); \
2376 static void throwArrayRegionOutOfBounds(ArrayObject* arrayObj, jsize start,
2377 jsize len, const char* arrayIdentifier)
2379 dvmThrowExceptionFmt(gDvm.exArrayIndexOutOfBoundsException,
2380 "%s offset=%d length=%d %s.length=%d",
2381 arrayObj->clazz->descriptor, start, len, arrayIdentifier,
2386 * Copy a section of a primitive array to a buffer.
2388 #define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
2389 static void Get##_jname##ArrayRegion(JNIEnv* env, \
2390 _ctype##Array jarr, jsize start, jsize len, _ctype* buf) \
2392 ScopedJniThreadState ts(env); \
2393 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2394 _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2395 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
2396 throwArrayRegionOutOfBounds(arrayObj, start, len, "src"); \
2398 memcpy(buf, data + start, len * sizeof(_ctype)); \
2403 * Copy a section of a primitive array from a buffer.
2405 #define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
2406 static void Set##_jname##ArrayRegion(JNIEnv* env, \
2407 _ctype##Array jarr, jsize start, jsize len, const _ctype* buf) \
2409 ScopedJniThreadState ts(env); \
2410 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2411 _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2412 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
2413 throwArrayRegionOutOfBounds(arrayObj, start, len, "dst"); \
2415 memcpy(data + start, buf, len * sizeof(_ctype)); \
2421 * Get<Type>ArrayElements
2422 * Release<Type>ArrayElements
2423 * Get<Type>ArrayRegion
2424 * Set<Type>ArrayRegion
2426 #define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname) \
2427 GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
2428 RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
2429 GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \
2430 SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
2432 PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean);
2433 PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte);
2434 PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char);
2435 PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short);
2436 PRIMITIVE_ARRAY_FUNCTIONS(jint, Int);
2437 PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long);
2438 PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float);
2439 PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double);
2442 * Register one or more native functions in one class.
2444 * This can be called multiple times on the same method, allowing the
2445 * caller to redefine the method implementation at will.
2447 static jint RegisterNatives(JNIEnv* env, jclass jclazz,
2448 const JNINativeMethod* methods, jint nMethods)
2450 ScopedJniThreadState ts(env);
2452 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
2454 if (gDvm.verboseJni) {
2455 ALOGI("[Registering JNI native methods for class %s]",
2459 for (int i = 0; i < nMethods; i++) {
2460 if (!dvmRegisterJNIMethod(clazz, methods[i].name,
2461 methods[i].signature, methods[i].fnPtr))
2470 * Un-register all native methods associated with the class.
2472 * The JNI docs refer to this as a way to reload/relink native libraries,
2473 * and say it "should not be used in normal native code". In particular,
2474 * there is no need to do this during shutdown, and you do not need to do
2475 * this before redefining a method implementation with RegisterNatives.
2477 * It's chiefly useful for a native "plugin"-style library that wasn't
2478 * loaded with System.loadLibrary() (since there's no way to unload those).
2479 * For example, the library could upgrade itself by:
2481 * 1. call UnregisterNatives to unbind the old methods
2482 * 2. ensure that no code is still executing inside it (somehow)
2483 * 3. dlclose() the library
2484 * 4. dlopen() the new library
2485 * 5. use RegisterNatives to bind the methods from the new library
2487 * The above can work correctly without the UnregisterNatives call, but
2488 * creates a window of opportunity in which somebody might try to call a
2489 * method that is pointing at unmapped memory, crashing the VM. In theory
2490 * the same guards that prevent dlclose() from unmapping executing code could
2491 * prevent that anyway, but with this we can be more thorough and also deal
2492 * with methods that only exist in the old or new form of the library (maybe
2493 * the lib wants to try the call and catch the UnsatisfiedLinkError).
2495 static jint UnregisterNatives(JNIEnv* env, jclass jclazz) {
2496 ScopedJniThreadState ts(env);
2498 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
2499 if (gDvm.verboseJni) {
2500 ALOGI("[Unregistering JNI native methods for class %s]",
2503 dvmUnregisterJNINativeMethods(clazz);
2510 * We have to track all monitor enters and exits, so that we can undo any
2511 * outstanding synchronization before the thread exits.
2513 static jint MonitorEnter(JNIEnv* env, jobject jobj) {
2514 ScopedJniThreadState ts(env);
2515 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
2516 dvmLockObject(ts.self(), obj);
2517 trackMonitorEnter(ts.self(), obj);
2522 * Unlock the monitor.
2524 * Throws an IllegalMonitorStateException if the current thread
2525 * doesn't own the monitor. (dvmUnlockObject() takes care of the throw.)
2527 * According to the 1.6 spec, it's legal to call here with an exception
2528 * pending. If this fails, we'll stomp the original exception.
2530 static jint MonitorExit(JNIEnv* env, jobject jobj) {
2531 ScopedJniThreadState ts(env);
2532 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
2533 bool success = dvmUnlockObject(ts.self(), obj);
2535 trackMonitorExit(ts.self(), obj);
2537 return success ? JNI_OK : JNI_ERR;
2541 * Return the JavaVM interface associated with the current thread.
2543 static jint GetJavaVM(JNIEnv* env, JavaVM** vm) {
2544 ScopedJniThreadState ts(env);
2545 *vm = gDvmJni.jniVm;
2546 return (*vm == NULL) ? JNI_ERR : JNI_OK;
2550 * Copies "len" Unicode characters, from offset "start".
2552 static void GetStringRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, jchar* buf) {
2553 ScopedJniThreadState ts(env);
2554 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2555 int strLen = strObj->length();
2556 if (((start|len) < 0) || (start + len > strLen)) {
2557 dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
2560 memcpy(buf, strObj->chars() + start, len * sizeof(u2));
2564 * Translates "len" Unicode characters, from offset "start", into
2565 * modified UTF-8 encoding.
2567 static void GetStringUTFRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, char* buf) {
2568 ScopedJniThreadState ts(env);
2569 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2570 int strLen = strObj->length();
2571 if (((start|len) < 0) || (start + len > strLen)) {
2572 dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
2575 dvmGetStringUtfRegion(strObj, start, len, buf);
2579 * Get a raw pointer to array data.
2581 * The caller is expected to call "release" before doing any JNI calls
2582 * or blocking I/O operations.
2584 * We need to pin the memory or block GC.
2586 static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray jarr, jboolean* isCopy) {
2587 ScopedJniThreadState ts(env);
2588 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2589 pinPrimitiveArray(arrayObj);
2590 void* data = arrayObj->contents;
2591 if (UNLIKELY(isCopy != NULL)) {
2592 *isCopy = JNI_FALSE;
2598 * Release an array obtained with GetPrimitiveArrayCritical.
2600 static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray jarr, void* carray, jint mode) {
2601 if (mode != JNI_COMMIT) {
2602 ScopedJniThreadState ts(env);
2603 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2604 unpinPrimitiveArray(arrayObj);
2609 * Like GetStringChars, but with restricted use.
2611 static const jchar* GetStringCritical(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2612 ScopedJniThreadState ts(env);
2614 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2615 ArrayObject* strChars = strObj->array();
2617 pinPrimitiveArray(strChars);
2619 const u2* data = strObj->chars();
2620 if (isCopy != NULL) {
2621 *isCopy = JNI_FALSE;
2623 return (jchar*) data;
2627 * Like ReleaseStringChars, but with restricted use.
2629 static void ReleaseStringCritical(JNIEnv* env, jstring jstr, const jchar* carray) {
2630 ScopedJniThreadState ts(env);
2631 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2632 ArrayObject* strChars = strObj->array();
2633 unpinPrimitiveArray(strChars);
2637 * Create a new weak global reference.
2639 static jweak NewWeakGlobalRef(JNIEnv* env, jobject jobj) {
2640 ScopedJniThreadState ts(env);
2641 Object *obj = dvmDecodeIndirectRef(ts.self(), jobj);
2642 return (jweak) addWeakGlobalReference(obj);
2646 * Delete the specified weak global reference.
2648 static void DeleteWeakGlobalRef(JNIEnv* env, jweak wref) {
2649 ScopedJniThreadState ts(env);
2650 deleteWeakGlobalReference(wref);
2654 * Quick check for pending exceptions.
2656 * TODO: we should be able to skip the enter/exit macros here.
2658 static jboolean ExceptionCheck(JNIEnv* env) {
2659 ScopedJniThreadState ts(env);
2660 return dvmCheckException(ts.self());
2664 * Returns the type of the object referred to by "obj". It can be local,
2665 * global, or weak global.
2667 * In the current implementation, references can be global and local at
2668 * the same time, so while the return value is accurate it may not tell
2671 static jobjectRefType GetObjectRefType(JNIEnv* env, jobject jobj) {
2672 ScopedJniThreadState ts(env);
2673 return dvmGetJNIRefType(ts.self(), jobj);
2677 * Allocate and return a new java.nio.ByteBuffer for this block of memory.
2679 static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
2680 ScopedJniThreadState ts(env);
2683 ALOGE("JNI ERROR (app bug): negative buffer capacity: %lld", capacity);
2686 if (address == NULL && capacity != 0) {
2687 ALOGE("JNI ERROR (app bug): non-zero capacity for NULL pointer: %lld", capacity);
2691 /* create an instance of java.nio.DirectByteBuffer */
2692 ClassObject* bufferClazz = gDvm.classJavaNioDirectByteBuffer;
2693 if (!dvmIsClassInitialized(bufferClazz) && !dvmInitClass(bufferClazz)) {
2696 Object* newObj = dvmAllocObject(bufferClazz, ALLOC_DONT_TRACK);
2697 if (newObj == NULL) {
2700 /* call the constructor */
2701 jobject result = addLocalReference(ts.self(), newObj);
2703 dvmCallMethod(ts.self(), gDvm.methJavaNioDirectByteBuffer_init,
2704 newObj, &unused, (jlong) address, (jint) capacity);
2705 if (dvmGetException(ts.self()) != NULL) {
2706 deleteLocalReference(ts.self(), result);
2713 * Get the starting address of the buffer for the specified java.nio.Buffer.
2715 * If this is not a "direct" buffer, we return NULL.
2717 static void* GetDirectBufferAddress(JNIEnv* env, jobject jbuf) {
2718 ScopedJniThreadState ts(env);
2720 // All Buffer objects have an effectiveDirectAddress field.
2721 Object* bufObj = dvmDecodeIndirectRef(ts.self(), jbuf);
2722 return (void*) dvmGetFieldLong(bufObj, gDvm.offJavaNioBuffer_effectiveDirectAddress);
2726 * Get the capacity of the buffer for the specified java.nio.Buffer.
2728 * Returns -1 if the object is not a direct buffer. (We actually skip
2729 * this check, since it's expensive to determine, and just return the
2730 * capacity regardless.)
2732 static jlong GetDirectBufferCapacity(JNIEnv* env, jobject jbuf) {
2733 ScopedJniThreadState ts(env);
2736 * The capacity is always in the Buffer.capacity field.
2738 * (The "check" version should verify that this is actually a Buffer,
2739 * but we're not required to do so here.)
2741 Object* buf = dvmDecodeIndirectRef(ts.self(), jbuf);
2742 return dvmGetFieldInt(buf, gDvm.offJavaNioBuffer_capacity);
2747 * ===========================================================================
2748 * JNI invocation functions
2749 * ===========================================================================
2753 * Handle AttachCurrentThread{AsDaemon}.
2755 * We need to make sure the VM is actually running. For example, if we start
2756 * up, issue an Attach, and the VM exits almost immediately, by the time the
2757 * attaching happens the VM could already be shutting down.
2759 * It's hard to avoid a race condition here because we don't want to hold
2760 * a lock across the entire operation. What we can do is temporarily
2761 * increment the thread count to prevent a VM exit.
2763 * This could potentially still have problems if a daemon thread calls here
2764 * while the VM is shutting down. dvmThreadSelf() will work, since it just
2765 * uses pthread TLS, but dereferencing "vm" could fail. Such is life when
2766 * you shut down a VM while threads are still running inside it.
2768 * Remember that some code may call this as a way to find the per-thread
2769 * JNIEnv pointer. Don't do excess work for that case.
2771 static jint attachThread(JavaVM* vm, JNIEnv** p_env, void* thr_args, bool isDaemon) {
2772 JavaVMAttachArgs* args = (JavaVMAttachArgs*) thr_args;
2775 * Return immediately if we're already one with the VM.
2777 Thread* self = dvmThreadSelf();
2779 *p_env = self->jniEnv;
2784 * No threads allowed in zygote mode.
2790 /* increment the count to keep the VM from bailing while we run */
2791 dvmLockThreadList(NULL);
2792 if (gDvm.nonDaemonThreadCount == 0) {
2794 ALOGV("Refusing to attach thread '%s' -- VM is shutting down",
2795 (thr_args == NULL) ? "(unknown)" : args->name);
2796 dvmUnlockThreadList();
2799 gDvm.nonDaemonThreadCount++;
2800 dvmUnlockThreadList();
2802 /* tweak the JavaVMAttachArgs as needed */
2803 JavaVMAttachArgs argsCopy;
2805 /* allow the v1.1 calling convention */
2806 argsCopy.version = JNI_VERSION_1_2;
2807 argsCopy.name = NULL;
2808 argsCopy.group = (jobject) dvmGetMainThreadGroup();
2810 argsCopy.version = args->version;
2811 argsCopy.name = args->name;
2812 if (args->group != NULL) {
2813 argsCopy.group = (jobject) dvmDecodeIndirectRef(NULL, args->group);
2815 argsCopy.group = (jobject) dvmGetMainThreadGroup();
2819 bool result = dvmAttachCurrentThread(&argsCopy, isDaemon);
2821 /* restore the count */
2822 dvmLockThreadList(NULL);
2823 gDvm.nonDaemonThreadCount--;
2824 dvmUnlockThreadList();
2827 * Change the status to indicate that we're out in native code. This
2828 * call is not guarded with state-change macros, so we have to do it
2832 self = dvmThreadSelf();
2833 assert(self != NULL);
2834 dvmChangeStatus(self, THREAD_NATIVE);
2835 *p_env = self->jniEnv;
2843 * Attach the current thread to the VM. If the thread is already attached,
2846 static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
2847 return attachThread(vm, p_env, thr_args, false);
2851 * Like AttachCurrentThread, but set the "daemon" flag.
2853 static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args)
2855 return attachThread(vm, p_env, thr_args, true);
2859 * Dissociate the current thread from the VM.
2861 static jint DetachCurrentThread(JavaVM* vm) {
2862 Thread* self = dvmThreadSelf();
2864 /* not attached, can't do anything */
2868 /* switch to "running" to check for suspension */
2869 dvmChangeStatus(self, THREAD_RUNNING);
2871 /* detach the thread */
2872 dvmDetachCurrentThread();
2874 /* (no need to change status back -- we have no status) */
2879 * If current thread is attached to VM, return the associated JNIEnv.
2880 * Otherwise, stuff NULL in and return JNI_EDETACHED.
2882 * JVMTI overloads this by specifying a magic value for "version", so we
2883 * do want to check that here.
2885 static jint GetEnv(JavaVM* vm, void** env, jint version) {
2886 Thread* self = dvmThreadSelf();
2888 if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6) {
2889 return JNI_EVERSION;
2895 /* TODO: status change is probably unnecessary */
2896 dvmChangeStatus(self, THREAD_RUNNING);
2897 *env = (void*) dvmGetThreadJNIEnv(self);
2898 dvmChangeStatus(self, THREAD_NATIVE);
2900 return (*env != NULL) ? JNI_OK : JNI_EDETACHED;
2904 * Destroy the VM. This may be called from any thread.
2906 * If the current thread is attached, wait until the current thread is
2907 * the only non-daemon user-level thread. If the current thread is not
2908 * attached, we attach it and do the processing as usual. (If the attach
2909 * fails, it's probably because all the non-daemon threads have already
2910 * exited and the VM doesn't want to let us back in.)
2912 * TODO: we don't really deal with the situation where more than one thread
2913 * has called here. One thread wins, the other stays trapped waiting on
2914 * the condition variable forever. Not sure this situation is interesting
2917 static jint DestroyJavaVM(JavaVM* vm) {
2918 JavaVMExt* ext = (JavaVMExt*) vm;
2923 if (gDvm.verboseShutdown) {
2924 ALOGD("DestroyJavaVM waiting for non-daemon threads to exit");
2928 * Sleep on a condition variable until it's okay to exit.
2930 Thread* self = dvmThreadSelf();
2933 if (AttachCurrentThread(vm, &tmpEnv, NULL) != JNI_OK) {
2934 ALOGV("Unable to reattach main for Destroy; assuming VM is shutting down (count=%d)",
2935 gDvm.nonDaemonThreadCount);
2938 ALOGV("Attached to wait for shutdown in Destroy");
2941 dvmChangeStatus(self, THREAD_VMWAIT);
2943 dvmLockThreadList(self);
2944 gDvm.nonDaemonThreadCount--; // remove current thread from count
2946 while (gDvm.nonDaemonThreadCount > 0) {
2947 pthread_cond_wait(&gDvm.vmExitCond, &gDvm.threadListLock);
2950 dvmUnlockThreadList();
2954 // TODO: call System.exit() to run any registered shutdown hooks
2955 // (this may not return -- figure out how this should work)
2957 if (gDvm.verboseShutdown) {
2958 ALOGD("DestroyJavaVM shutting VM down");
2962 // TODO - free resources associated with JNI-attached daemon threads
2971 * ===========================================================================
2973 * ===========================================================================
2976 static const struct JNINativeInterface gNativeInterface = {
2987 FromReflectedMethod,
3011 EnsureLocalCapacity,
3054 CallNonvirtualObjectMethod,
3055 CallNonvirtualObjectMethodV,
3056 CallNonvirtualObjectMethodA,
3057 CallNonvirtualBooleanMethod,
3058 CallNonvirtualBooleanMethodV,
3059 CallNonvirtualBooleanMethodA,
3060 CallNonvirtualByteMethod,
3061 CallNonvirtualByteMethodV,
3062 CallNonvirtualByteMethodA,
3063 CallNonvirtualCharMethod,
3064 CallNonvirtualCharMethodV,
3065 CallNonvirtualCharMethodA,
3066 CallNonvirtualShortMethod,
3067 CallNonvirtualShortMethodV,
3068 CallNonvirtualShortMethodA,
3069 CallNonvirtualIntMethod,
3070 CallNonvirtualIntMethodV,
3071 CallNonvirtualIntMethodA,
3072 CallNonvirtualLongMethod,
3073 CallNonvirtualLongMethodV,
3074 CallNonvirtualLongMethodA,
3075 CallNonvirtualFloatMethod,
3076 CallNonvirtualFloatMethodV,
3077 CallNonvirtualFloatMethodA,
3078 CallNonvirtualDoubleMethod,
3079 CallNonvirtualDoubleMethodV,
3080 CallNonvirtualDoubleMethodA,
3081 CallNonvirtualVoidMethod,
3082 CallNonvirtualVoidMethodV,
3083 CallNonvirtualVoidMethodA,
3108 CallStaticObjectMethod,
3109 CallStaticObjectMethodV,
3110 CallStaticObjectMethodA,
3111 CallStaticBooleanMethod,
3112 CallStaticBooleanMethodV,
3113 CallStaticBooleanMethodA,
3114 CallStaticByteMethod,
3115 CallStaticByteMethodV,
3116 CallStaticByteMethodA,
3117 CallStaticCharMethod,
3118 CallStaticCharMethodV,
3119 CallStaticCharMethodA,
3120 CallStaticShortMethod,
3121 CallStaticShortMethodV,
3122 CallStaticShortMethodA,
3123 CallStaticIntMethod,
3124 CallStaticIntMethodV,
3125 CallStaticIntMethodA,
3126 CallStaticLongMethod,
3127 CallStaticLongMethodV,
3128 CallStaticLongMethodA,
3129 CallStaticFloatMethod,
3130 CallStaticFloatMethodV,
3131 CallStaticFloatMethodA,
3132 CallStaticDoubleMethod,
3133 CallStaticDoubleMethodV,
3134 CallStaticDoubleMethodA,
3135 CallStaticVoidMethod,
3136 CallStaticVoidMethodV,
3137 CallStaticVoidMethodA,
3141 GetStaticObjectField,
3142 GetStaticBooleanField,
3145 GetStaticShortField,
3148 GetStaticFloatField,
3149 GetStaticDoubleField,
3151 SetStaticObjectField,
3152 SetStaticBooleanField,
3155 SetStaticShortField,
3158 SetStaticFloatField,
3159 SetStaticDoubleField,
3170 ReleaseStringUTFChars,
3174 GetObjectArrayElement,
3175 SetObjectArrayElement,
3186 GetBooleanArrayElements,
3187 GetByteArrayElements,
3188 GetCharArrayElements,
3189 GetShortArrayElements,
3190 GetIntArrayElements,
3191 GetLongArrayElements,
3192 GetFloatArrayElements,
3193 GetDoubleArrayElements,
3195 ReleaseBooleanArrayElements,
3196 ReleaseByteArrayElements,
3197 ReleaseCharArrayElements,
3198 ReleaseShortArrayElements,
3199 ReleaseIntArrayElements,
3200 ReleaseLongArrayElements,
3201 ReleaseFloatArrayElements,
3202 ReleaseDoubleArrayElements,
3204 GetBooleanArrayRegion,
3207 GetShortArrayRegion,
3210 GetFloatArrayRegion,
3211 GetDoubleArrayRegion,
3212 SetBooleanArrayRegion,
3215 SetShortArrayRegion,
3218 SetFloatArrayRegion,
3219 SetDoubleArrayRegion,
3232 GetPrimitiveArrayCritical,
3233 ReleasePrimitiveArrayCritical,
3236 ReleaseStringCritical,
3239 DeleteWeakGlobalRef,
3243 NewDirectByteBuffer,
3244 GetDirectBufferAddress,
3245 GetDirectBufferCapacity,
3250 static const struct JNIInvokeInterface gInvokeInterface = {
3256 AttachCurrentThread,
3257 DetachCurrentThread,
3261 AttachCurrentThreadAsDaemon,
3265 * ===========================================================================
3267 * ===========================================================================
3271 * Create a new JNIEnv struct and add it to the VM's list.
3273 * "self" will be NULL for the main thread, since the VM hasn't started
3274 * yet; the value will be filled in later.
3276 JNIEnv* dvmCreateJNIEnv(Thread* self) {
3277 JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
3280 // ALOGI("Ent CreateJNIEnv: threadid=%d %p", self->threadId, self);
3284 JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
3285 newEnv->funcTable = &gNativeInterface;
3287 dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
3288 assert(newEnv->envThreadId != 0);
3290 /* make it obvious if we fail to initialize these later */
3291 newEnv->envThreadId = 0x77777775;
3292 newEnv->self = (Thread*) 0x77777779;
3294 if (gDvmJni.useCheckJni) {
3295 dvmUseCheckedJniEnv(newEnv);
3298 ScopedPthreadMutexLock lock(&vm->envListLock);
3300 /* insert at head of list */
3301 newEnv->next = vm->envList;
3302 assert(newEnv->prev == NULL);
3303 if (vm->envList == NULL) {
3304 // rare, but possible
3305 vm->envList = newEnv;
3307 vm->envList->prev = newEnv;
3309 vm->envList = newEnv;
3312 // ALOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self);
3313 return (JNIEnv*) newEnv;
3317 * Remove a JNIEnv struct from the list and free it.
3319 void dvmDestroyJNIEnv(JNIEnv* env) {
3324 //ALOGI("Ent DestroyJNIEnv: threadid=%d %p", self->threadId, self);
3326 JNIEnvExt* extEnv = (JNIEnvExt*) env;
3327 JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
3329 ScopedPthreadMutexLock lock(&vm->envListLock);
3331 if (extEnv == vm->envList) {
3332 assert(extEnv->prev == NULL);
3333 vm->envList = extEnv->next;
3335 assert(extEnv->prev != NULL);
3336 extEnv->prev->next = extEnv->next;
3338 if (extEnv->next != NULL) {
3339 extEnv->next->prev = extEnv->prev;
3343 //ALOGI("Xit DestroyJNIEnv: threadid=%d %p", self->threadId, self);
3347 * Enable "checked JNI" after the VM has partially started. This must
3348 * only be called in "zygote" mode, when we have one thread running.
3350 * This doesn't attempt to rewrite the JNI call bridge associated with
3351 * native methods, so we won't get those checks for any methods that have
3352 * already been resolved.
3354 void dvmLateEnableCheckedJni() {
3355 JNIEnvExt* extEnv = dvmGetJNIEnvForThread();
3356 if (extEnv == NULL) {
3357 ALOGE("dvmLateEnableCheckedJni: thread has no JNIEnv");
3360 JavaVMExt* extVm = (JavaVMExt*) gDvmJni.jniVm;
3361 assert(extVm != NULL);
3363 if (!gDvmJni.useCheckJni) {
3364 ALOGD("Late-enabling CheckJNI");
3365 dvmUseCheckedJniVm(extVm);
3366 dvmUseCheckedJniEnv(extEnv);
3368 ALOGD("Not late-enabling CheckJNI (already on)");
3375 jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
3380 * Return a buffer full of created VMs.
3382 * We always have zero or one.
3384 jint JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs) {
3385 if (gDvmJni.jniVm != NULL) {
3388 *vmBuf++ = gDvmJni.jniVm;
3397 * Create a new VM instance.
3399 * The current thread becomes the main VM thread. We return immediately,
3400 * which effectively means the caller is executing in a native method.
3402 jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
3403 const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args;
3404 if (args->version < JNI_VERSION_1_2) {
3405 return JNI_EVERSION;
3408 // TODO: don't allow creation of multiple VMs -- one per customer for now
3410 /* zero globals; not strictly necessary the first time a VM is started */
3411 memset(&gDvm, 0, sizeof(gDvm));
3414 * Set up structures for JNIEnv and VM.
3416 JavaVMExt* pVM = (JavaVMExt*) calloc(1, sizeof(JavaVMExt));
3417 pVM->funcTable = &gInvokeInterface;
3418 pVM->envList = NULL;
3419 dvmInitMutex(&pVM->envListLock);
3421 UniquePtr<const char*[]> argv(new const char*[args->nOptions]);
3422 memset(argv.get(), 0, sizeof(char*) * (args->nOptions));
3425 * Convert JNI args to argv.
3427 * We have to pull out vfprintf/exit/abort, because they use the
3428 * "extraInfo" field to pass function pointer "hooks" in. We also
3429 * look for the -Xcheck:jni stuff here.
3432 for (int i = 0; i < args->nOptions; i++) {
3433 const char* optStr = args->options[i].optionString;
3434 if (optStr == NULL) {
3435 dvmFprintf(stderr, "ERROR: CreateJavaVM failed: argument %d was NULL\n", i);
3437 } else if (strcmp(optStr, "vfprintf") == 0) {
3438 gDvm.vfprintfHook = (int (*)(FILE *, const char*, va_list))args->options[i].extraInfo;
3439 } else if (strcmp(optStr, "exit") == 0) {
3440 gDvm.exitHook = (void (*)(int)) args->options[i].extraInfo;
3441 } else if (strcmp(optStr, "abort") == 0) {
3442 gDvm.abortHook = (void (*)(void))args->options[i].extraInfo;
3443 } else if (strcmp(optStr, "sensitiveThread") == 0) {
3444 gDvm.isSensitiveThreadHook = (bool (*)(void))args->options[i].extraInfo;
3445 } else if (strcmp(optStr, "-Xcheck:jni") == 0) {
3446 gDvmJni.useCheckJni = true;
3447 } else if (strncmp(optStr, "-Xjniopts:", 10) == 0) {
3448 char* jniOpts = strdup(optStr + 10);
3449 size_t jniOptCount = 1;
3450 for (char* p = jniOpts; *p != 0; ++p) {
3456 char* jniOpt = jniOpts;
3457 for (size_t i = 0; i < jniOptCount; ++i) {
3458 if (strcmp(jniOpt, "warnonly") == 0) {
3459 gDvmJni.warnOnly = true;
3460 } else if (strcmp(jniOpt, "forcecopy") == 0) {
3461 gDvmJni.forceCopy = true;
3462 } else if (strcmp(jniOpt, "logThirdPartyJni") == 0) {
3463 gDvmJni.logThirdPartyJni = true;
3465 dvmFprintf(stderr, "ERROR: CreateJavaVM failed: unknown -Xjniopts option '%s'\n",
3471 jniOpt += strlen(jniOpt) + 1;
3475 /* regular option */
3476 argv[argc++] = optStr;
3480 if (gDvmJni.useCheckJni) {
3481 dvmUseCheckedJniVm(pVM);
3484 if (gDvmJni.jniVm != NULL) {
3485 dvmFprintf(stderr, "ERROR: Dalvik only supports one VM per process\n");
3489 gDvmJni.jniVm = (JavaVM*) pVM;
3492 * Create a JNIEnv for the main thread. We need to have something set up
3493 * here because some of the class initialization we do when starting
3494 * up the VM will call into native code.
3496 JNIEnvExt* pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);
3498 /* Initialize VM. */
3499 gDvm.initializing = true;
3500 std::string status =
3501 dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);
3502 gDvm.initializing = false;
3504 if (!status.empty()) {
3507 ALOGW("CreateJavaVM failed: %s", status.c_str());
3512 * Success! Return stuff to caller.
3514 dvmChangeStatus(NULL, THREAD_NATIVE);
3515 *p_env = (JNIEnv*) pEnv;
3516 *p_vm = (JavaVM*) pVM;
3517 ALOGV("CreateJavaVM succeeded");