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);
696 static void throwNoSuchMethodError(ClassObject* c, const char* name, const char* sig, const char* kind) {
697 std::string msg(StringPrintf("no %s method \"%s.%s%s\"", kind, c->descriptor, name, sig));
698 dvmThrowNoSuchMethodError(msg.c_str());
702 * Register a method that uses JNI calling conventions.
704 static bool dvmRegisterJNIMethod(ClassObject* clazz, const char* methodName,
705 const char* signature, void* fnPtr)
711 // If a signature starts with a '!', we take that as a sign that the native code doesn't
712 // need the extra JNI arguments (the JNIEnv* and the jclass).
713 bool fastJni = false;
714 if (*signature == '!') {
717 ALOGV("fast JNI method %s.%s:%s detected", clazz->descriptor, methodName, signature);
720 Method* method = dvmFindDirectMethodByDescriptor(clazz, methodName, signature);
721 if (method == NULL) {
722 method = dvmFindVirtualMethodByDescriptor(clazz, methodName, signature);
724 if (method == NULL) {
725 dumpCandidateMethods(clazz, methodName, signature);
726 throwNoSuchMethodError(clazz, methodName, signature, "static or non-static");
730 if (!dvmIsNativeMethod(method)) {
731 ALOGW("Unable to register: not native: %s.%s:%s", clazz->descriptor, methodName, signature);
732 throwNoSuchMethodError(clazz, methodName, signature, "native");
737 // In this case, we have extra constraints to check...
738 if (dvmIsSynchronizedMethod(method)) {
739 // Synchronization is usually provided by the JNI bridge,
740 // but we won't have one.
741 ALOGE("fast JNI method %s.%s:%s cannot be synchronized",
742 clazz->descriptor, methodName, signature);
745 if (!dvmIsStaticMethod(method)) {
746 // There's no real reason for this constraint, but since we won't
747 // be supplying a JNIEnv* or a jobject 'this', you're effectively
748 // static anyway, so it seems clearer to say so.
749 ALOGE("fast JNI method %s.%s:%s cannot be non-static",
750 clazz->descriptor, methodName, signature);
755 if (method->nativeFunc != dvmResolveNativeMethod) {
756 /* this is allowed, but unusual */
757 ALOGV("Note: %s.%s:%s was already registered", clazz->descriptor, methodName, signature);
760 method->fastJni = fastJni;
761 dvmUseJNIBridge(method, fnPtr);
763 ALOGV("JNI-registered %s.%s:%s", clazz->descriptor, methodName, signature);
767 static const char* builtInPrefixes[] = {
770 "Lcom/google/android/",
775 "Lorg/apache/harmony/",
778 static bool shouldTrace(Method* method) {
779 const char* className = method->clazz->descriptor;
780 // Return true if the -Xjnitrace setting implies we should trace 'method'.
781 if (gDvm.jniTrace && strstr(className, gDvm.jniTrace)) {
784 // Return true if we're trying to log all third-party JNI activity and 'method' doesn't look
785 // like part of Android.
786 if (gDvmJni.logThirdPartyJni) {
787 for (size_t i = 0; i < NELEM(builtInPrefixes); ++i) {
788 if (strstr(className, builtInPrefixes[i]) == className) {
798 * Point "method->nativeFunc" at the JNI bridge, and overload "method->insns"
799 * to point at the actual function.
801 void dvmUseJNIBridge(Method* method, void* func) {
802 method->shouldTrace = shouldTrace(method);
804 // Does the method take any reference arguments?
805 method->noRef = true;
806 const char* cp = method->shorty;
807 while (*++cp != '\0') { // Pre-increment to skip return type.
809 method->noRef = false;
814 DalvikBridgeFunc bridge = gDvmJni.useCheckJni ? dvmCheckCallJNIMethod : dvmCallJNIMethod;
815 dvmSetNativeFunc(method, bridge, (const u2*) func);
818 // TODO: rewrite this to share code with CheckJNI's tracing...
819 static void appendValue(char type, const JValue value, char* buf, size_t n, bool appendComma)
821 size_t len = strlen(buf);
822 if (len >= n - 32) { // 32 should be longer than anything we could append.
831 if (value.b >= 0 && value.b < 10) {
832 sprintf(p, "%d", value.b);
834 sprintf(p, "%#x (%d)", value.b, value.b);
838 if (value.c < 0x7f && value.c >= ' ') {
839 sprintf(p, "U+%x ('%c')", value.c, value.c);
841 sprintf(p, "U+%x", value.c);
845 sprintf(p, "%g", value.d);
848 sprintf(p, "%g", value.f);
851 sprintf(p, "%d", value.i);
854 sprintf(p, "%#x", value.i);
857 sprintf(p, "%lld", value.j);
860 sprintf(p, "%d", value.s);
866 strcpy(p, value.z ? "true" : "false");
869 sprintf(p, "unknown type '%c'", type);
878 static void logNativeMethodEntry(const Method* method, const u4* args)
880 char thisString[32] = { 0 };
882 if (!dvmIsStaticMethod(method)) {
883 sprintf(thisString, "this=0x%08x ", *sp++);
886 char argsString[128]= { 0 };
887 const char* desc = &method->shorty[1];
888 while (*desc != '\0') {
889 char argType = *desc++;
891 if (argType == 'D' || argType == 'J') {
892 value.j = dvmGetArgLong(sp, 0);
897 appendValue(argType, value, argsString, sizeof(argsString),
901 std::string className(dvmHumanReadableDescriptor(method->clazz->descriptor));
902 char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
903 ALOGI("-> %s %s%s %s(%s)", className.c_str(), method->name, signature, thisString, argsString);
907 static void logNativeMethodExit(const Method* method, Thread* self, const JValue returnValue)
909 std::string className(dvmHumanReadableDescriptor(method->clazz->descriptor));
910 char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
911 if (dvmCheckException(self)) {
912 Object* exception = dvmGetException(self);
913 std::string exceptionClassName(dvmHumanReadableDescriptor(exception->clazz->descriptor));
914 ALOGI("<- %s %s%s threw %s", className.c_str(),
915 method->name, signature, exceptionClassName.c_str());
917 char returnValueString[128] = { 0 };
918 char returnType = method->shorty[0];
919 appendValue(returnType, returnValue, returnValueString, sizeof(returnValueString), false);
920 ALOGI("<- %s %s%s returned %s", className.c_str(),
921 method->name, signature, returnValueString);
927 * Get the method currently being executed by examining the interp stack.
929 const Method* dvmGetCurrentJNIMethod() {
930 assert(dvmThreadSelf() != NULL);
932 void* fp = dvmThreadSelf()->interpSave.curFrame;
933 const Method* meth = SAVEAREA_FROM_FP(fp)->method;
935 assert(meth != NULL);
936 assert(dvmIsNativeMethod(meth));
941 * Track a JNI MonitorEnter in the current thread.
943 * The goal is to be able to "implicitly" release all JNI-held monitors
944 * when the thread detaches.
946 * Monitors may be entered multiple times, so we add a new entry for each
947 * enter call. It would be more efficient to keep a counter. At present
948 * there's no real motivation to improve this however.
950 static void trackMonitorEnter(Thread* self, Object* obj) {
951 static const int kInitialSize = 16;
952 ReferenceTable* refTable = &self->jniMonitorRefTable;
954 /* init table on first use */
955 if (refTable->table == NULL) {
956 assert(refTable->maxEntries == 0);
958 if (!dvmInitReferenceTable(refTable, kInitialSize, INT_MAX)) {
959 ALOGE("Unable to initialize monitor tracking table");
964 if (!dvmAddToReferenceTable(refTable, obj)) {
965 /* ran out of memory? could throw exception instead */
966 ALOGE("Unable to add entry to monitor tracking table");
969 LOGVV("--- added monitor %p", obj);
974 * Track a JNI MonitorExit in the current thread.
976 static void trackMonitorExit(Thread* self, Object* obj) {
977 ReferenceTable* pRefTable = &self->jniMonitorRefTable;
979 if (!dvmRemoveFromReferenceTable(pRefTable, pRefTable->table, obj)) {
980 ALOGE("JNI monitor %p not found in tracking list", obj);
983 LOGVV("--- removed monitor %p", obj);
988 * Release all monitors held by the jniMonitorRefTable list.
990 void dvmReleaseJniMonitors(Thread* self) {
991 ReferenceTable* pRefTable = &self->jniMonitorRefTable;
992 Object** top = pRefTable->table;
997 Object** ptr = pRefTable->nextEntry;
998 while (--ptr >= top) {
999 if (!dvmUnlockObject(self, *ptr)) {
1000 ALOGW("Unable to unlock monitor %p at thread detach", *ptr);
1002 LOGVV("--- detach-releasing monitor %p", *ptr);
1007 pRefTable->nextEntry = pRefTable->table;
1011 * Determine if the specified class can be instantiated from JNI. This
1012 * is used by AllocObject / NewObject, which are documented as throwing
1013 * an exception for abstract and interface classes, and not accepting
1014 * array classes. We also want to reject attempts to create new Class
1015 * objects, since only DefineClass should do that.
1017 static bool canAllocClass(ClassObject* clazz) {
1018 if (dvmIsAbstractClass(clazz) || dvmIsInterfaceClass(clazz)) {
1019 /* JNI spec defines what this throws */
1020 dvmThrowInstantiationException(clazz, "abstract class or interface");
1022 } else if (dvmIsArrayClass(clazz) || dvmIsTheClassClass(clazz)) {
1023 /* spec says "must not" for arrays, ignores Class */
1024 dvmThrowInstantiationException(clazz, "wrong JNI function");
1032 * ===========================================================================
1034 * ===========================================================================
1038 * The functions here form a bridge between interpreted code and JNI native
1039 * functions. The basic task is to convert an array of primitives and
1040 * references into C-style function arguments. This is architecture-specific
1041 * and usually requires help from assembly code.
1043 * The bridge takes four arguments: the array of parameters, a place to
1044 * store the function result (if any), the method to call, and a pointer
1045 * to the current thread.
1047 * These functions aren't called directly from elsewhere in the VM.
1048 * A pointer in the Method struct points to one of these, and when a native
1049 * method is invoked the interpreter jumps to it.
1051 * (The "internal native" methods are invoked the same way, but instead
1052 * of calling through a bridge, the target method is called directly.)
1054 * The "args" array should not be modified, but we do so anyway for
1055 * performance reasons. We know that it points to the "outs" area on
1056 * the current method's interpreted stack. This area is ignored by the
1057 * precise GC, because there is no register map for a native method (for
1058 * an interpreted method the args would be listed in the argument set).
1059 * We know all of the values exist elsewhere on the interpreted stack,
1060 * because the method call setup copies them right before making the call,
1061 * so we don't have to worry about concealing stuff from the GC.
1063 * If we don't want to modify "args", we either have to create a local
1064 * copy and modify it before calling dvmPlatformInvoke, or we have to do
1065 * the local reference replacement within dvmPlatformInvoke. The latter
1066 * has some performance advantages, though if we can inline the local
1067 * reference adds we may win when there's a lot of reference args (unless
1068 * we want to code up some local ref table manipulation in assembly.
1072 * If necessary, convert the value in pResult from a local/global reference
1073 * to an object pointer.
1075 * If the returned reference is invalid, kInvalidIndirectRefObject will
1076 * be returned in pResult.
1078 static inline void convertReferenceResult(JNIEnv* env, JValue* pResult,
1079 const Method* method, Thread* self)
1081 if (method->shorty[0] == 'L' && !dvmCheckException(self) && pResult->l != NULL) {
1082 pResult->l = dvmDecodeIndirectRef(self, (jobject) pResult->l);
1087 * General form, handles all cases.
1089 void dvmCallJNIMethod(const u4* args, JValue* pResult, const Method* method, Thread* self) {
1090 u4* modArgs = (u4*) args;
1091 jclass staticMethodClass = NULL;
1093 u4 accessFlags = method->accessFlags;
1094 bool isSynchronized = (accessFlags & ACC_SYNCHRONIZED) != 0;
1096 //ALOGI("JNI calling %p (%s.%s:%s):", method->insns,
1097 // method->clazz->descriptor, method->name, method->shorty);
1100 * Walk the argument list, creating local references for appropriate
1105 if ((accessFlags & ACC_STATIC) != 0) {
1106 lockObj = (Object*) method->clazz;
1107 /* add the class object we pass in */
1108 staticMethodClass = (jclass) addLocalReference(self, (Object*) method->clazz);
1110 lockObj = (Object*) args[0];
1112 modArgs[idx++] = (u4) addLocalReference(self, (Object*) modArgs[0]);
1115 if (!method->noRef) {
1116 const char* shorty = &method->shorty[1]; /* skip return type */
1117 while (*shorty != '\0') {
1118 switch (*shorty++) {
1120 //ALOGI(" local %d: 0x%08x", idx, modArgs[idx]);
1121 if (modArgs[idx] != 0) {
1122 modArgs[idx] = (u4) addLocalReference(self, (Object*) modArgs[idx]);
1130 /* Z B C S I -- do nothing */
1137 if (UNLIKELY(method->shouldTrace)) {
1138 logNativeMethodEntry(method, args);
1140 if (UNLIKELY(isSynchronized)) {
1141 dvmLockObject(self, lockObj);
1144 ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
1146 ANDROID_MEMBAR_FULL(); /* guarantee ordering on method->insns */
1147 assert(method->insns != NULL);
1149 JNIEnv* env = self->jniEnv;
1150 COMPUTE_STACK_SUM(self);
1151 dvmPlatformInvoke(env,
1152 (ClassObject*) staticMethodClass,
1153 method->jniArgInfo, method->insSize, modArgs, method->shorty,
1154 (void*) method->insns, pResult);
1155 CHECK_STACK_SUM(self);
1157 dvmChangeStatus(self, oldStatus);
1159 convertReferenceResult(env, pResult, method, self);
1161 if (UNLIKELY(isSynchronized)) {
1162 dvmUnlockObject(self, lockObj);
1164 if (UNLIKELY(method->shouldTrace)) {
1165 logNativeMethodExit(method, self, *pResult);
1170 * ===========================================================================
1171 * JNI implementation
1172 * ===========================================================================
1176 * Return the version of the native method interface.
1178 static jint GetVersion(JNIEnv* env) {
1180 * There is absolutely no need to toggle the mode for correct behavior.
1181 * However, it does provide native code with a simple "suspend self
1182 * if necessary" call.
1184 ScopedJniThreadState ts(env);
1185 return JNI_VERSION_1_6;
1189 * Create a new class from a bag of bytes.
1191 * This is not currently supported within Dalvik.
1193 static jclass DefineClass(JNIEnv* env, const char *name, jobject loader,
1194 const jbyte* buf, jsize bufLen)
1196 UNUSED_PARAMETER(name);
1197 UNUSED_PARAMETER(loader);
1198 UNUSED_PARAMETER(buf);
1199 UNUSED_PARAMETER(bufLen);
1201 ScopedJniThreadState ts(env);
1202 ALOGW("JNI DefineClass is not supported");
1207 * Find a class by name.
1209 * We have to use the "no init" version of FindClass here, because we might
1210 * be getting the class prior to registering native methods that will be
1213 * We need to get the class loader associated with the current native
1214 * method. If there is no native method, e.g. we're calling this from native
1215 * code right after creating the VM, the spec says we need to use the class
1216 * loader returned by "ClassLoader.getBaseClassLoader". There is no such
1217 * method, but it's likely they meant ClassLoader.getSystemClassLoader.
1218 * We can't get that until after the VM has initialized though.
1220 static jclass FindClass(JNIEnv* env, const char* name) {
1221 ScopedJniThreadState ts(env);
1223 const Method* thisMethod = dvmGetCurrentJNIMethod();
1224 assert(thisMethod != NULL);
1227 Object* trackedLoader = NULL;
1228 if (ts.self()->classLoaderOverride != NULL) {
1229 /* hack for JNI_OnLoad */
1230 assert(strcmp(thisMethod->name, "nativeLoad") == 0);
1231 loader = ts.self()->classLoaderOverride;
1232 } else if (thisMethod == gDvm.methDalvikSystemNativeStart_main ||
1233 thisMethod == gDvm.methDalvikSystemNativeStart_run) {
1234 /* start point of invocation interface */
1235 if (!gDvm.initializing) {
1236 loader = trackedLoader = dvmGetSystemClassLoader();
1241 loader = thisMethod->clazz->classLoader;
1244 char* descriptor = dvmNameToDescriptor(name);
1245 if (descriptor == NULL) {
1248 ClassObject* clazz = dvmFindClassNoInit(descriptor, loader);
1251 jclass jclazz = (jclass) addLocalReference(ts.self(), (Object*) clazz);
1252 dvmReleaseTrackedAlloc(trackedLoader, ts.self());
1257 * Return the superclass of a class.
1259 static jclass GetSuperclass(JNIEnv* env, jclass jclazz) {
1260 ScopedJniThreadState ts(env);
1261 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1262 return (jclass) addLocalReference(ts.self(), (Object*)clazz->super);
1266 * Determine whether an object of clazz1 can be safely cast to clazz2.
1268 * Like IsInstanceOf, but with a pair of class objects instead of obj+class.
1270 static jboolean IsAssignableFrom(JNIEnv* env, jclass jclazz1, jclass jclazz2) {
1271 ScopedJniThreadState ts(env);
1272 ClassObject* clazz1 = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz1);
1273 ClassObject* clazz2 = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz2);
1274 return dvmInstanceof(clazz1, clazz2);
1278 * Given a java.lang.reflect.Method or .Constructor, return a methodID.
1280 static jmethodID FromReflectedMethod(JNIEnv* env, jobject jmethod) {
1281 ScopedJniThreadState ts(env);
1282 Object* method = dvmDecodeIndirectRef(ts.self(), jmethod);
1283 return (jmethodID) dvmGetMethodFromReflectObj(method);
1287 * Given a java.lang.reflect.Field, return a fieldID.
1289 static jfieldID FromReflectedField(JNIEnv* env, jobject jfield) {
1290 ScopedJniThreadState ts(env);
1291 Object* field = dvmDecodeIndirectRef(ts.self(), jfield);
1292 return (jfieldID) dvmGetFieldFromReflectObj(field);
1296 * Convert a methodID to a java.lang.reflect.Method or .Constructor.
1298 * (The "isStatic" field does not appear in the spec.)
1300 * Throws OutOfMemory and returns NULL on failure.
1302 static jobject ToReflectedMethod(JNIEnv* env, jclass jcls, jmethodID methodID, jboolean isStatic) {
1303 ScopedJniThreadState ts(env);
1304 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jcls);
1305 Object* obj = dvmCreateReflectObjForMethod(clazz, (Method*) methodID);
1306 dvmReleaseTrackedAlloc(obj, NULL);
1307 return addLocalReference(ts.self(), obj);
1311 * Convert a fieldID to a java.lang.reflect.Field.
1313 * (The "isStatic" field does not appear in the spec.)
1315 * Throws OutOfMemory and returns NULL on failure.
1317 static jobject ToReflectedField(JNIEnv* env, jclass jcls, jfieldID fieldID, jboolean isStatic) {
1318 ScopedJniThreadState ts(env);
1319 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jcls);
1320 Object* obj = dvmCreateReflectObjForField(clazz, (Field*) fieldID);
1321 dvmReleaseTrackedAlloc(obj, NULL);
1322 return addLocalReference(ts.self(), obj);
1326 * Take this exception and throw it.
1328 static jint Throw(JNIEnv* env, jthrowable jobj) {
1329 ScopedJniThreadState ts(env);
1331 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1332 dvmSetException(ts.self(), obj);
1339 * Constructs an exception object from the specified class with the message
1340 * specified by "message", and throws it.
1342 static jint ThrowNew(JNIEnv* env, jclass jclazz, const char* message) {
1343 ScopedJniThreadState ts(env);
1344 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1345 dvmThrowException(clazz, message);
1346 // TODO: should return failure if this didn't work (e.g. OOM)
1351 * If an exception is being thrown, return the exception object. Otherwise,
1354 * TODO: if there is no pending exception, we should be able to skip the
1355 * enter/exit checks. If we find one, we need to enter and then re-fetch
1356 * the exception (in case it got moved by a compacting GC).
1358 static jthrowable ExceptionOccurred(JNIEnv* env) {
1359 ScopedJniThreadState ts(env);
1360 Object* exception = dvmGetException(ts.self());
1361 jthrowable localException = (jthrowable) addLocalReference(ts.self(), exception);
1362 if (localException == NULL && exception != NULL) {
1364 * We were unable to add a new local reference, and threw a new
1365 * exception. We can't return "exception", because it's not a
1366 * local reference. So we have to return NULL, indicating that
1367 * there was no exception, even though it's pretty much raining
1368 * exceptions in here.
1370 ALOGW("JNI WARNING: addLocal/exception combo");
1372 return localException;
1376 * Print an exception and stack trace to stderr.
1378 static void ExceptionDescribe(JNIEnv* env) {
1379 ScopedJniThreadState ts(env);
1380 Object* exception = dvmGetException(ts.self());
1381 if (exception != NULL) {
1382 dvmPrintExceptionStackTrace();
1384 ALOGI("Odd: ExceptionDescribe called, but no exception pending");
1389 * Clear the exception currently being thrown.
1391 * TODO: we should be able to skip the enter/exit stuff.
1393 static void ExceptionClear(JNIEnv* env) {
1394 ScopedJniThreadState ts(env);
1395 dvmClearException(ts.self());
1399 * Kill the VM. This function does not return.
1401 static void FatalError(JNIEnv* env, const char* msg) {
1402 //dvmChangeStatus(NULL, THREAD_RUNNING);
1403 ALOGE("JNI posting fatal error: %s", msg);
1408 * Push a new JNI frame on the stack, with a new set of locals.
1410 * The new frame must have the same method pointer. (If for no other
1411 * reason than FindClass needs it to get the appropriate class loader.)
1413 static jint PushLocalFrame(JNIEnv* env, jint capacity) {
1414 ScopedJniThreadState ts(env);
1415 if (!ensureLocalCapacity(ts.self(), capacity) ||
1416 !dvmPushLocalFrame(ts.self(), dvmGetCurrentJNIMethod()))
1418 /* yes, OutOfMemoryError, not StackOverflowError */
1419 dvmClearException(ts.self());
1420 dvmThrowOutOfMemoryError("out of stack in JNI PushLocalFrame");
1427 * Pop the local frame off. If "jresult" is not null, add it as a
1428 * local reference on the now-current frame.
1430 static jobject PopLocalFrame(JNIEnv* env, jobject jresult) {
1431 ScopedJniThreadState ts(env);
1432 Object* result = dvmDecodeIndirectRef(ts.self(), jresult);
1433 if (!dvmPopLocalFrame(ts.self())) {
1434 ALOGW("JNI WARNING: too many PopLocalFrame calls");
1435 dvmClearException(ts.self());
1436 dvmThrowRuntimeException("too many PopLocalFrame calls");
1438 return addLocalReference(ts.self(), result);
1442 * Add a reference to the global list.
1444 static jobject NewGlobalRef(JNIEnv* env, jobject jobj) {
1445 ScopedJniThreadState ts(env);
1446 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1447 return addGlobalReference(obj);
1451 * Delete a reference from the global list.
1453 static void DeleteGlobalRef(JNIEnv* env, jobject jglobalRef) {
1454 ScopedJniThreadState ts(env);
1455 deleteGlobalReference(jglobalRef);
1460 * Add a reference to the local list.
1462 static jobject NewLocalRef(JNIEnv* env, jobject jobj) {
1463 ScopedJniThreadState ts(env);
1464 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1465 return addLocalReference(ts.self(), obj);
1469 * Delete a reference from the local list.
1471 static void DeleteLocalRef(JNIEnv* env, jobject jlocalRef) {
1472 ScopedJniThreadState ts(env);
1473 deleteLocalReference(ts.self(), jlocalRef);
1477 * Ensure that the local references table can hold at least this many
1480 static jint EnsureLocalCapacity(JNIEnv* env, jint capacity) {
1481 ScopedJniThreadState ts(env);
1482 bool okay = ensureLocalCapacity(ts.self(), capacity);
1484 dvmThrowOutOfMemoryError("can't ensure local reference capacity");
1486 return okay ? 0 : -1;
1491 * Determine whether two Object references refer to the same underlying object.
1493 static jboolean IsSameObject(JNIEnv* env, jobject jref1, jobject jref2) {
1494 ScopedJniThreadState ts(env);
1495 Object* obj1 = dvmDecodeIndirectRef(ts.self(), jref1);
1496 Object* obj2 = dvmDecodeIndirectRef(ts.self(), jref2);
1497 return (obj1 == obj2);
1501 * Allocate a new object without invoking any constructors.
1503 static jobject AllocObject(JNIEnv* env, jclass jclazz) {
1504 ScopedJniThreadState ts(env);
1506 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1507 if (!canAllocClass(clazz) ||
1508 (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)))
1510 assert(dvmCheckException(ts.self()));
1514 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1515 return addLocalReference(ts.self(), newObj);
1519 * Allocate a new object and invoke the supplied constructor.
1521 static jobject NewObject(JNIEnv* env, jclass jclazz, jmethodID methodID, ...) {
1522 ScopedJniThreadState ts(env);
1523 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1525 if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
1526 assert(dvmCheckException(ts.self()));
1530 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1531 jobject result = addLocalReference(ts.self(), newObj);
1532 if (newObj != NULL) {
1535 va_start(args, methodID);
1536 dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args);
1542 static jobject NewObjectV(JNIEnv* env, jclass jclazz, jmethodID methodID, va_list args) {
1543 ScopedJniThreadState ts(env);
1544 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1546 if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
1547 assert(dvmCheckException(ts.self()));
1551 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1552 jobject result = addLocalReference(ts.self(), newObj);
1553 if (newObj != NULL) {
1555 dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args);
1560 static jobject NewObjectA(JNIEnv* env, jclass jclazz, jmethodID methodID, jvalue* args) {
1561 ScopedJniThreadState ts(env);
1562 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1564 if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
1565 assert(dvmCheckException(ts.self()));
1569 Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1570 jobject result = addLocalReference(ts.self(), newObj);
1571 if (newObj != NULL) {
1573 dvmCallMethodA(ts.self(), (Method*) methodID, newObj, true, &unused, args);
1579 * Returns the class of an object.
1581 * JNI spec says: obj must not be NULL.
1583 static jclass GetObjectClass(JNIEnv* env, jobject jobj) {
1584 ScopedJniThreadState ts(env);
1586 assert(jobj != NULL);
1588 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1589 return (jclass) addLocalReference(ts.self(), (Object*) obj->clazz);
1593 * Determine whether "obj" is an instance of "clazz".
1595 static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass jclazz) {
1596 ScopedJniThreadState ts(env);
1598 assert(jclazz != NULL);
1603 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1604 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1605 return dvmInstanceof(obj->clazz, clazz);
1609 * Get a method ID for an instance method.
1611 * While Dalvik bytecode has distinct instructions for virtual, super,
1612 * static, direct, and interface method invocation, JNI only provides
1613 * two functions for acquiring a method ID. This call handles everything
1614 * but static methods.
1616 * JNI defines <init> as an instance method, but Dalvik considers it a
1617 * "direct" method, so we have to special-case it here.
1619 * Dalvik also puts all private methods into the "direct" list, so we
1620 * really need to just search both lists.
1622 static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1623 ScopedJniThreadState ts(env);
1625 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1626 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1627 assert(dvmCheckException(ts.self()));
1628 } else if (dvmIsInterfaceClass(clazz)) {
1629 Method* meth = dvmFindInterfaceMethodHierByDescriptor(clazz, name, sig);
1631 dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
1632 "no method with name='%s' signature='%s' in interface %s",
1633 name, sig, clazz->descriptor);
1635 return (jmethodID) meth;
1637 Method* meth = dvmFindVirtualMethodHierByDescriptor(clazz, name, sig);
1639 /* search private methods and constructors; non-hierarchical */
1640 meth = dvmFindDirectMethodByDescriptor(clazz, name, sig);
1642 if (meth != NULL && dvmIsStaticMethod(meth)) {
1644 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
1645 ALOGD("GetMethodID: not returning static method %s.%s %s",
1646 clazz->descriptor, meth->name, desc);
1652 dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
1653 "no method with name='%s' signature='%s' in class %s",
1654 name, sig, clazz->descriptor);
1657 * The method's class may not be the same as clazz, but if
1658 * it isn't this must be a virtual method and the class must
1659 * be a superclass (and, hence, already initialized).
1661 assert(dvmIsClassInitialized(meth->clazz) || dvmIsClassInitializing(meth->clazz));
1663 return (jmethodID) meth;
1667 * Get a field ID (instance fields).
1669 static jfieldID GetFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1670 ScopedJniThreadState ts(env);
1672 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1674 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1675 assert(dvmCheckException(ts.self()));
1679 jfieldID id = (jfieldID) dvmFindInstanceFieldHier(clazz, name, sig);
1681 dvmThrowExceptionFmt(gDvm.exNoSuchFieldError,
1682 "no field with name='%s' signature='%s' in class %s",
1683 name, sig, clazz->descriptor);
1689 * Get the method ID for a static method in a class.
1691 static jmethodID GetStaticMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1692 ScopedJniThreadState ts(env);
1694 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1695 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1696 assert(dvmCheckException(ts.self()));
1700 Method* meth = dvmFindDirectMethodHierByDescriptor(clazz, name, sig);
1702 /* make sure it's static, not virtual+private */
1703 if (meth != NULL && !dvmIsStaticMethod(meth)) {
1705 char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
1706 ALOGD("GetStaticMethodID: not returning nonstatic method %s.%s %s",
1707 clazz->descriptor, meth->name, desc);
1713 jmethodID id = (jmethodID) meth;
1715 dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
1716 "no static method with name='%s' signature='%s' in class %s",
1717 name, sig, clazz->descriptor);
1723 * Get a field ID (static fields).
1725 static jfieldID GetStaticFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1726 ScopedJniThreadState ts(env);
1728 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1729 if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1730 assert(dvmCheckException(ts.self()));
1734 jfieldID id = (jfieldID) dvmFindStaticFieldHier(clazz, name, sig);
1736 dvmThrowExceptionFmt(gDvm.exNoSuchFieldError,
1737 "no static field with name='%s' signature='%s' in class %s",
1738 name, sig, clazz->descriptor);
1744 * Get a static field.
1746 * If we get an object reference, add it to the local refs list.
1748 #define GET_STATIC_TYPE_FIELD(_ctype, _jname, _isref) \
1749 static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass jclazz, \
1752 UNUSED_PARAMETER(jclazz); \
1753 ScopedJniThreadState ts(env); \
1754 StaticField* sfield = (StaticField*) fieldID; \
1756 if (dvmIsVolatileField(sfield)) { \
1757 if (_isref) { /* only when _ctype==jobject */ \
1758 Object* obj = dvmGetStaticFieldObjectVolatile(sfield); \
1759 value = (_ctype)(u4)addLocalReference(ts.self(), obj); \
1761 value = (_ctype) dvmGetStaticField##_jname##Volatile(sfield);\
1765 Object* obj = dvmGetStaticFieldObject(sfield); \
1766 value = (_ctype)(u4)addLocalReference(ts.self(), obj); \
1768 value = (_ctype) dvmGetStaticField##_jname(sfield); \
1773 GET_STATIC_TYPE_FIELD(jobject, Object, true);
1774 GET_STATIC_TYPE_FIELD(jboolean, Boolean, false);
1775 GET_STATIC_TYPE_FIELD(jbyte, Byte, false);
1776 GET_STATIC_TYPE_FIELD(jchar, Char, false);
1777 GET_STATIC_TYPE_FIELD(jshort, Short, false);
1778 GET_STATIC_TYPE_FIELD(jint, Int, false);
1779 GET_STATIC_TYPE_FIELD(jlong, Long, false);
1780 GET_STATIC_TYPE_FIELD(jfloat, Float, false);
1781 GET_STATIC_TYPE_FIELD(jdouble, Double, false);
1784 * Set a static field.
1786 #define SET_STATIC_TYPE_FIELD(_ctype, _ctype2, _jname, _isref) \
1787 static void SetStatic##_jname##Field(JNIEnv* env, jclass jclazz, \
1788 jfieldID fieldID, _ctype value) \
1790 UNUSED_PARAMETER(jclazz); \
1791 ScopedJniThreadState ts(env); \
1792 StaticField* sfield = (StaticField*) fieldID; \
1793 if (dvmIsVolatileField(sfield)) { \
1794 if (_isref) { /* only when _ctype==jobject */ \
1795 Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1796 dvmSetStaticFieldObjectVolatile(sfield, valObj); \
1798 dvmSetStaticField##_jname##Volatile(sfield, (_ctype2)value);\
1802 Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1803 dvmSetStaticFieldObject(sfield, valObj); \
1805 dvmSetStaticField##_jname(sfield, (_ctype2)value); \
1809 SET_STATIC_TYPE_FIELD(jobject, Object*, Object, true);
1810 SET_STATIC_TYPE_FIELD(jboolean, bool, Boolean, false);
1811 SET_STATIC_TYPE_FIELD(jbyte, s1, Byte, false);
1812 SET_STATIC_TYPE_FIELD(jchar, u2, Char, false);
1813 SET_STATIC_TYPE_FIELD(jshort, s2, Short, false);
1814 SET_STATIC_TYPE_FIELD(jint, s4, Int, false);
1815 SET_STATIC_TYPE_FIELD(jlong, s8, Long, false);
1816 SET_STATIC_TYPE_FIELD(jfloat, float, Float, false);
1817 SET_STATIC_TYPE_FIELD(jdouble, double, Double, false);
1820 * Get an instance field.
1822 * If we get an object reference, add it to the local refs list.
1824 #define GET_TYPE_FIELD(_ctype, _jname, _isref) \
1825 static _ctype Get##_jname##Field(JNIEnv* env, jobject jobj, \
1828 ScopedJniThreadState ts(env); \
1829 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1830 InstField* field = (InstField*) fieldID; \
1832 if (dvmIsVolatileField(field)) { \
1833 if (_isref) { /* only when _ctype==jobject */ \
1835 dvmGetFieldObjectVolatile(obj, field->byteOffset); \
1836 value = (_ctype)(u4)addLocalReference(ts.self(), valObj); \
1839 dvmGetField##_jname##Volatile(obj, field->byteOffset); \
1843 Object* valObj = dvmGetFieldObject(obj, field->byteOffset); \
1844 value = (_ctype)(u4)addLocalReference(ts.self(), valObj); \
1846 value = (_ctype) dvmGetField##_jname(obj, field->byteOffset);\
1851 GET_TYPE_FIELD(jobject, Object, true);
1852 GET_TYPE_FIELD(jboolean, Boolean, false);
1853 GET_TYPE_FIELD(jbyte, Byte, false);
1854 GET_TYPE_FIELD(jchar, Char, false);
1855 GET_TYPE_FIELD(jshort, Short, false);
1856 GET_TYPE_FIELD(jint, Int, false);
1857 GET_TYPE_FIELD(jlong, Long, false);
1858 GET_TYPE_FIELD(jfloat, Float, false);
1859 GET_TYPE_FIELD(jdouble, Double, false);
1862 * Set an instance field.
1864 #define SET_TYPE_FIELD(_ctype, _ctype2, _jname, _isref) \
1865 static void Set##_jname##Field(JNIEnv* env, jobject jobj, \
1866 jfieldID fieldID, _ctype value) \
1868 ScopedJniThreadState ts(env); \
1869 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1870 InstField* field = (InstField*) fieldID; \
1871 if (dvmIsVolatileField(field)) { \
1872 if (_isref) { /* only when _ctype==jobject */ \
1873 Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1874 dvmSetFieldObjectVolatile(obj, field->byteOffset, valObj); \
1876 dvmSetField##_jname##Volatile(obj, \
1877 field->byteOffset, (_ctype2)value); \
1881 Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1882 dvmSetFieldObject(obj, field->byteOffset, valObj); \
1884 dvmSetField##_jname(obj, \
1885 field->byteOffset, (_ctype2)value); \
1889 SET_TYPE_FIELD(jobject, Object*, Object, true);
1890 SET_TYPE_FIELD(jboolean, bool, Boolean, false);
1891 SET_TYPE_FIELD(jbyte, s1, Byte, false);
1892 SET_TYPE_FIELD(jchar, u2, Char, false);
1893 SET_TYPE_FIELD(jshort, s2, Short, false);
1894 SET_TYPE_FIELD(jint, s4, Int, false);
1895 SET_TYPE_FIELD(jlong, s8, Long, false);
1896 SET_TYPE_FIELD(jfloat, float, Float, false);
1897 SET_TYPE_FIELD(jdouble, double, Double, false);
1900 * Make a virtual method call.
1902 * Three versions (..., va_list, jvalue[]) for each return type. If we're
1903 * returning an Object, we have to add it to the local references table.
1905 #define CALL_VIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \
1906 static _ctype Call##_jname##Method(JNIEnv* env, jobject jobj, \
1907 jmethodID methodID, ...) \
1909 ScopedJniThreadState ts(env); \
1910 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1911 const Method* meth; \
1914 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
1915 if (meth == NULL) { \
1918 va_start(args, methodID); \
1919 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \
1921 if (_isref && !dvmCheckException(ts.self())) \
1922 result.l = (Object*)addLocalReference(ts.self(), result.l); \
1925 static _ctype Call##_jname##MethodV(JNIEnv* env, jobject jobj, \
1926 jmethodID methodID, va_list args) \
1928 ScopedJniThreadState ts(env); \
1929 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1930 const Method* meth; \
1932 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
1933 if (meth == NULL) { \
1936 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \
1937 if (_isref && !dvmCheckException(ts.self())) \
1938 result.l = (Object*)addLocalReference(ts.self(), result.l); \
1941 static _ctype Call##_jname##MethodA(JNIEnv* env, jobject jobj, \
1942 jmethodID methodID, jvalue* args) \
1944 ScopedJniThreadState ts(env); \
1945 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1946 const Method* meth; \
1948 meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID); \
1949 if (meth == NULL) { \
1952 dvmCallMethodA(ts.self(), meth, obj, true, &result, args); \
1953 if (_isref && !dvmCheckException(ts.self())) \
1954 result.l = (Object*)addLocalReference(ts.self(), result.l); \
1957 CALL_VIRTUAL(jobject, Object, NULL, (jobject) result.l, true);
1958 CALL_VIRTUAL(jboolean, Boolean, 0, result.z, false);
1959 CALL_VIRTUAL(jbyte, Byte, 0, result.b, false);
1960 CALL_VIRTUAL(jchar, Char, 0, result.c, false);
1961 CALL_VIRTUAL(jshort, Short, 0, result.s, false);
1962 CALL_VIRTUAL(jint, Int, 0, result.i, false);
1963 CALL_VIRTUAL(jlong, Long, 0, result.j, false);
1964 CALL_VIRTUAL(jfloat, Float, 0.0f, result.f, false);
1965 CALL_VIRTUAL(jdouble, Double, 0.0, result.d, false);
1966 CALL_VIRTUAL(void, Void, , , false);
1969 * Make a "non-virtual" method call. We're still calling a virtual method,
1970 * but this time we're not doing an indirection through the object's vtable.
1971 * The "clazz" parameter defines which implementation of a method we want.
1973 * Three versions (..., va_list, jvalue[]) for each return type.
1975 #define CALL_NONVIRTUAL(_ctype, _jname, _retfail, _retok, _isref) \
1976 static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, jobject jobj, \
1977 jclass jclazz, jmethodID methodID, ...) \
1979 ScopedJniThreadState ts(env); \
1980 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1981 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz); \
1982 const Method* meth; \
1985 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
1986 if (meth == NULL) { \
1989 va_start(args, methodID); \
1990 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \
1991 if (_isref && !dvmCheckException(ts.self())) \
1992 result.l = (Object*)addLocalReference(ts.self(), result.l); \
1996 static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, jobject jobj,\
1997 jclass jclazz, jmethodID methodID, va_list args) \
1999 ScopedJniThreadState ts(env); \
2000 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
2001 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz); \
2002 const Method* meth; \
2004 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
2005 if (meth == NULL) { \
2008 dvmCallMethodV(ts.self(), meth, obj, true, &result, args); \
2009 if (_isref && !dvmCheckException(ts.self())) \
2010 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2013 static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, jobject jobj,\
2014 jclass jclazz, jmethodID methodID, jvalue* args) \
2016 ScopedJniThreadState ts(env); \
2017 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
2018 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz); \
2019 const Method* meth; \
2021 meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID); \
2022 if (meth == NULL) { \
2025 dvmCallMethodA(ts.self(), meth, obj, true, &result, args); \
2026 if (_isref && !dvmCheckException(ts.self())) \
2027 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2030 CALL_NONVIRTUAL(jobject, Object, NULL, (jobject) result.l, true);
2031 CALL_NONVIRTUAL(jboolean, Boolean, 0, result.z, false);
2032 CALL_NONVIRTUAL(jbyte, Byte, 0, result.b, false);
2033 CALL_NONVIRTUAL(jchar, Char, 0, result.c, false);
2034 CALL_NONVIRTUAL(jshort, Short, 0, result.s, false);
2035 CALL_NONVIRTUAL(jint, Int, 0, result.i, false);
2036 CALL_NONVIRTUAL(jlong, Long, 0, result.j, false);
2037 CALL_NONVIRTUAL(jfloat, Float, 0.0f, result.f, false);
2038 CALL_NONVIRTUAL(jdouble, Double, 0.0, result.d, false);
2039 CALL_NONVIRTUAL(void, Void, , , false);
2043 * Call a static method.
2045 #define CALL_STATIC(_ctype, _jname, _retfail, _retok, _isref) \
2046 static _ctype CallStatic##_jname##Method(JNIEnv* env, jclass jclazz, \
2047 jmethodID methodID, ...) \
2049 UNUSED_PARAMETER(jclazz); \
2050 ScopedJniThreadState ts(env); \
2053 va_start(args, methodID); \
2054 dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
2056 if (_isref && !dvmCheckException(ts.self())) \
2057 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2060 static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass jclazz, \
2061 jmethodID methodID, va_list args) \
2063 UNUSED_PARAMETER(jclazz); \
2064 ScopedJniThreadState ts(env); \
2066 dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
2067 if (_isref && !dvmCheckException(ts.self())) \
2068 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2071 static _ctype CallStatic##_jname##MethodA(JNIEnv* env, jclass jclazz, \
2072 jmethodID methodID, jvalue* args) \
2074 UNUSED_PARAMETER(jclazz); \
2075 ScopedJniThreadState ts(env); \
2077 dvmCallMethodA(ts.self(), (Method*)methodID, NULL, true, &result, args);\
2078 if (_isref && !dvmCheckException(ts.self())) \
2079 result.l = (Object*)addLocalReference(ts.self(), result.l); \
2082 CALL_STATIC(jobject, Object, NULL, (jobject) result.l, true);
2083 CALL_STATIC(jboolean, Boolean, 0, result.z, false);
2084 CALL_STATIC(jbyte, Byte, 0, result.b, false);
2085 CALL_STATIC(jchar, Char, 0, result.c, false);
2086 CALL_STATIC(jshort, Short, 0, result.s, false);
2087 CALL_STATIC(jint, Int, 0, result.i, false);
2088 CALL_STATIC(jlong, Long, 0, result.j, false);
2089 CALL_STATIC(jfloat, Float, 0.0f, result.f, false);
2090 CALL_STATIC(jdouble, Double, 0.0, result.d, false);
2091 CALL_STATIC(void, Void, , , false);
2094 * Create a new String from Unicode data.
2096 * If "len" is zero, we will return an empty string even if "unicodeChars"
2097 * is NULL. (The JNI spec is vague here.)
2099 static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) {
2100 ScopedJniThreadState ts(env);
2101 StringObject* jstr = dvmCreateStringFromUnicode(unicodeChars, len);
2105 dvmReleaseTrackedAlloc((Object*) jstr, NULL);
2106 return (jstring) addLocalReference(ts.self(), (Object*) jstr);
2110 * Return the length of a String in Unicode character units.
2112 static jsize GetStringLength(JNIEnv* env, jstring jstr) {
2113 ScopedJniThreadState ts(env);
2114 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2115 return strObj->length();
2120 * Get a string's character data.
2122 * The result is guaranteed to be valid until ReleaseStringChars is
2123 * called, which means we have to pin it or return a copy.
2125 static const jchar* GetStringChars(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2126 ScopedJniThreadState ts(env);
2128 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2129 ArrayObject* strChars = strObj->array();
2131 pinPrimitiveArray(strChars);
2133 const u2* data = strObj->chars();
2134 if (isCopy != NULL) {
2135 *isCopy = JNI_FALSE;
2137 return (jchar*) data;
2141 * Release our grip on some characters from a string.
2143 static void ReleaseStringChars(JNIEnv* env, jstring jstr, const jchar* chars) {
2144 ScopedJniThreadState ts(env);
2145 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2146 ArrayObject* strChars = strObj->array();
2147 unpinPrimitiveArray(strChars);
2151 * Create a new java.lang.String object from chars in modified UTF-8 form.
2153 * The spec doesn't say how to handle a NULL string. Popular desktop VMs
2154 * accept it and return a NULL pointer in response.
2156 static jstring NewStringUTF(JNIEnv* env, const char* bytes) {
2157 ScopedJniThreadState ts(env);
2158 if (bytes == NULL) {
2161 /* note newStr could come back NULL on OOM */
2162 StringObject* newStr = dvmCreateStringFromCstr(bytes);
2163 jstring result = (jstring) addLocalReference(ts.self(), (Object*) newStr);
2164 dvmReleaseTrackedAlloc((Object*)newStr, NULL);
2169 * Return the length in bytes of the modified UTF-8 form of the string.
2171 static jsize GetStringUTFLength(JNIEnv* env, jstring jstr) {
2172 ScopedJniThreadState ts(env);
2173 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2174 if (strObj == NULL) {
2175 return 0; // Should we throw something or assert?
2177 return strObj->utfLength();
2181 * Convert "string" to modified UTF-8 and return a pointer. The returned
2182 * value must be released with ReleaseStringUTFChars.
2184 * According to the JNI reference, "Returns a pointer to a UTF-8 string,
2185 * or NULL if the operation fails. Returns NULL if and only if an invocation
2186 * of this function has thrown an exception."
2188 * The behavior here currently follows that of other open-source VMs, which
2189 * quietly return NULL if "string" is NULL. We should consider throwing an
2190 * NPE. (The CheckJNI code blows up if you try to pass in a NULL string,
2191 * which should catch this sort of thing during development.) Certain other
2192 * VMs will crash with a segmentation fault.
2194 static const char* GetStringUTFChars(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2195 ScopedJniThreadState ts(env);
2197 /* this shouldn't happen; throw NPE? */
2200 if (isCopy != NULL) {
2203 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2204 char* newStr = dvmCreateCstrFromString(strObj);
2205 if (newStr == NULL) {
2206 /* assume memory failure */
2207 dvmThrowOutOfMemoryError("native heap string alloc failed");
2213 * Release a string created by GetStringUTFChars().
2215 static void ReleaseStringUTFChars(JNIEnv* env, jstring jstr, const char* utf) {
2216 ScopedJniThreadState ts(env);
2221 * Return the capacity of the array.
2223 static jsize GetArrayLength(JNIEnv* env, jarray jarr) {
2224 ScopedJniThreadState ts(env);
2225 ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2226 return arrObj->length;
2230 * Construct a new array that holds objects from class "elementClass".
2232 static jobjectArray NewObjectArray(JNIEnv* env, jsize length,
2233 jclass jelementClass, jobject jinitialElement)
2235 ScopedJniThreadState ts(env);
2237 if (jelementClass == NULL) {
2238 dvmThrowNullPointerException("JNI NewObjectArray elementClass == NULL");
2242 ClassObject* elemClassObj = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jelementClass);
2243 ClassObject* arrayClass = dvmFindArrayClassForElement(elemClassObj);
2244 ArrayObject* newObj = dvmAllocArrayByClass(arrayClass, length, ALLOC_DEFAULT);
2245 if (newObj == NULL) {
2246 assert(dvmCheckException(ts.self()));
2249 jobjectArray newArray = (jobjectArray) addLocalReference(ts.self(), (Object*) newObj);
2250 dvmReleaseTrackedAlloc((Object*) newObj, NULL);
2253 * Initialize the array.
2255 if (jinitialElement != NULL) {
2256 Object* initialElement = dvmDecodeIndirectRef(ts.self(), jinitialElement);
2257 Object** arrayData = (Object**) (void*) newObj->contents;
2258 for (jsize i = 0; i < length; ++i) {
2259 arrayData[i] = initialElement;
2266 static bool checkArrayElementBounds(ArrayObject* arrayObj, jsize index) {
2267 assert(arrayObj != NULL);
2268 if (index < 0 || index >= (int) arrayObj->length) {
2269 dvmThrowArrayIndexOutOfBoundsException(arrayObj->length, index);
2276 * Get one element of an Object array.
2278 * Add the object to the local references table in case the array goes away.
2280 static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index) {
2281 ScopedJniThreadState ts(env);
2283 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2284 if (!checkArrayElementBounds(arrayObj, index)) {
2288 Object* value = ((Object**) (void*) arrayObj->contents)[index];
2289 return addLocalReference(ts.self(), value);
2293 * Set one element of an Object array.
2295 static void SetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index, jobject jobj) {
2296 ScopedJniThreadState ts(env);
2298 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2299 if (!checkArrayElementBounds(arrayObj, index)) {
2303 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
2305 if (obj != NULL && !dvmCanPutArrayElement(obj->clazz, arrayObj->clazz)) {
2306 ALOGV("Can't put a '%s'(%p) into array type='%s'(%p)",
2307 obj->clazz->descriptor, obj,
2308 arrayObj->clazz->descriptor, arrayObj);
2309 dvmThrowArrayStoreExceptionIncompatibleElement(obj->clazz, arrayObj->clazz);
2313 //ALOGV("JNI: set element %d in array %p to %p", index, array, value);
2315 dvmSetObjectArrayElement(arrayObj, index, obj);
2319 * Create a new array of primitive elements.
2321 #define NEW_PRIMITIVE_ARRAY(_artype, _jname, _typechar) \
2322 static _artype New##_jname##Array(JNIEnv* env, jsize length) { \
2323 ScopedJniThreadState ts(env); \
2324 ArrayObject* arrayObj = dvmAllocPrimitiveArray(_typechar, length, ALLOC_DEFAULT); \
2325 if (arrayObj == NULL) { \
2328 _artype result = (_artype) addLocalReference(ts.self(), (Object*) arrayObj); \
2329 dvmReleaseTrackedAlloc((Object*) arrayObj, NULL); \
2332 NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean, 'Z');
2333 NEW_PRIMITIVE_ARRAY(jbyteArray, Byte, 'B');
2334 NEW_PRIMITIVE_ARRAY(jcharArray, Char, 'C');
2335 NEW_PRIMITIVE_ARRAY(jshortArray, Short, 'S');
2336 NEW_PRIMITIVE_ARRAY(jintArray, Int, 'I');
2337 NEW_PRIMITIVE_ARRAY(jlongArray, Long, 'J');
2338 NEW_PRIMITIVE_ARRAY(jfloatArray, Float, 'F');
2339 NEW_PRIMITIVE_ARRAY(jdoubleArray, Double, 'D');
2342 * Get a pointer to a C array of primitive elements from an array object
2343 * of the matching type.
2345 * In a compacting GC, we either need to return a copy of the elements or
2346 * "pin" the memory. Otherwise we run the risk of native code using the
2347 * buffer as the destination of e.g. a blocking read() call that wakes up
2350 #define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
2351 static _ctype* Get##_jname##ArrayElements(JNIEnv* env, \
2352 _ctype##Array jarr, jboolean* isCopy) \
2354 ScopedJniThreadState ts(env); \
2355 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2356 pinPrimitiveArray(arrayObj); \
2357 _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2358 if (isCopy != NULL) { \
2359 *isCopy = JNI_FALSE; \
2365 * Release the storage locked down by the "get" function.
2367 * The spec says, "'mode' has no effect if 'elems' is not a copy of the
2368 * elements in 'array'." They apparently did not anticipate the need to
2371 #define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
2372 static void Release##_jname##ArrayElements(JNIEnv* env, \
2373 _ctype##Array jarr, _ctype* elems, jint mode) \
2375 UNUSED_PARAMETER(elems); \
2376 if (mode != JNI_COMMIT) { \
2377 ScopedJniThreadState ts(env); \
2378 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2379 unpinPrimitiveArray(arrayObj); \
2383 static void throwArrayRegionOutOfBounds(ArrayObject* arrayObj, jsize start,
2384 jsize len, const char* arrayIdentifier)
2386 dvmThrowExceptionFmt(gDvm.exArrayIndexOutOfBoundsException,
2387 "%s offset=%d length=%d %s.length=%d",
2388 arrayObj->clazz->descriptor, start, len, arrayIdentifier,
2393 * Copy a section of a primitive array to a buffer.
2395 #define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
2396 static void Get##_jname##ArrayRegion(JNIEnv* env, \
2397 _ctype##Array jarr, jsize start, jsize len, _ctype* buf) \
2399 ScopedJniThreadState ts(env); \
2400 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2401 _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2402 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
2403 throwArrayRegionOutOfBounds(arrayObj, start, len, "src"); \
2405 memcpy(buf, data + start, len * sizeof(_ctype)); \
2410 * Copy a section of a primitive array from a buffer.
2412 #define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
2413 static void Set##_jname##ArrayRegion(JNIEnv* env, \
2414 _ctype##Array jarr, jsize start, jsize len, const _ctype* buf) \
2416 ScopedJniThreadState ts(env); \
2417 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2418 _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2419 if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
2420 throwArrayRegionOutOfBounds(arrayObj, start, len, "dst"); \
2422 memcpy(data + start, buf, len * sizeof(_ctype)); \
2428 * Get<Type>ArrayElements
2429 * Release<Type>ArrayElements
2430 * Get<Type>ArrayRegion
2431 * Set<Type>ArrayRegion
2433 #define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname) \
2434 GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
2435 RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
2436 GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \
2437 SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
2439 PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean);
2440 PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte);
2441 PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char);
2442 PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short);
2443 PRIMITIVE_ARRAY_FUNCTIONS(jint, Int);
2444 PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long);
2445 PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float);
2446 PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double);
2449 * Register one or more native functions in one class.
2451 * This can be called multiple times on the same method, allowing the
2452 * caller to redefine the method implementation at will.
2454 static jint RegisterNatives(JNIEnv* env, jclass jclazz,
2455 const JNINativeMethod* methods, jint nMethods)
2457 ScopedJniThreadState ts(env);
2459 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
2461 if (gDvm.verboseJni) {
2462 ALOGI("[Registering JNI native methods for class %s]",
2466 for (int i = 0; i < nMethods; i++) {
2467 if (!dvmRegisterJNIMethod(clazz, methods[i].name,
2468 methods[i].signature, methods[i].fnPtr))
2477 * Un-register all native methods associated with the class.
2479 * The JNI docs refer to this as a way to reload/relink native libraries,
2480 * and say it "should not be used in normal native code". In particular,
2481 * there is no need to do this during shutdown, and you do not need to do
2482 * this before redefining a method implementation with RegisterNatives.
2484 * It's chiefly useful for a native "plugin"-style library that wasn't
2485 * loaded with System.loadLibrary() (since there's no way to unload those).
2486 * For example, the library could upgrade itself by:
2488 * 1. call UnregisterNatives to unbind the old methods
2489 * 2. ensure that no code is still executing inside it (somehow)
2490 * 3. dlclose() the library
2491 * 4. dlopen() the new library
2492 * 5. use RegisterNatives to bind the methods from the new library
2494 * The above can work correctly without the UnregisterNatives call, but
2495 * creates a window of opportunity in which somebody might try to call a
2496 * method that is pointing at unmapped memory, crashing the VM. In theory
2497 * the same guards that prevent dlclose() from unmapping executing code could
2498 * prevent that anyway, but with this we can be more thorough and also deal
2499 * with methods that only exist in the old or new form of the library (maybe
2500 * the lib wants to try the call and catch the UnsatisfiedLinkError).
2502 static jint UnregisterNatives(JNIEnv* env, jclass jclazz) {
2503 ScopedJniThreadState ts(env);
2505 ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
2506 if (gDvm.verboseJni) {
2507 ALOGI("[Unregistering JNI native methods for class %s]",
2510 dvmUnregisterJNINativeMethods(clazz);
2517 * We have to track all monitor enters and exits, so that we can undo any
2518 * outstanding synchronization before the thread exits.
2520 static jint MonitorEnter(JNIEnv* env, jobject jobj) {
2521 ScopedJniThreadState ts(env);
2522 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
2523 dvmLockObject(ts.self(), obj);
2524 trackMonitorEnter(ts.self(), obj);
2529 * Unlock the monitor.
2531 * Throws an IllegalMonitorStateException if the current thread
2532 * doesn't own the monitor. (dvmUnlockObject() takes care of the throw.)
2534 * According to the 1.6 spec, it's legal to call here with an exception
2535 * pending. If this fails, we'll stomp the original exception.
2537 static jint MonitorExit(JNIEnv* env, jobject jobj) {
2538 ScopedJniThreadState ts(env);
2539 Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
2540 bool success = dvmUnlockObject(ts.self(), obj);
2542 trackMonitorExit(ts.self(), obj);
2544 return success ? JNI_OK : JNI_ERR;
2548 * Return the JavaVM interface associated with the current thread.
2550 static jint GetJavaVM(JNIEnv* env, JavaVM** vm) {
2551 ScopedJniThreadState ts(env);
2552 *vm = gDvmJni.jniVm;
2553 return (*vm == NULL) ? JNI_ERR : JNI_OK;
2557 * Copies "len" Unicode characters, from offset "start".
2559 static void GetStringRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, jchar* buf) {
2560 ScopedJniThreadState ts(env);
2561 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2562 int strLen = strObj->length();
2563 if (((start|len) < 0) || (start + len > strLen)) {
2564 dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
2567 memcpy(buf, strObj->chars() + start, len * sizeof(u2));
2571 * Translates "len" Unicode characters, from offset "start", into
2572 * modified UTF-8 encoding.
2574 static void GetStringUTFRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, char* buf) {
2575 ScopedJniThreadState ts(env);
2576 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2577 int strLen = strObj->length();
2578 if (((start|len) < 0) || (start + len > strLen)) {
2579 dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
2582 dvmGetStringUtfRegion(strObj, start, len, buf);
2586 * Get a raw pointer to array data.
2588 * The caller is expected to call "release" before doing any JNI calls
2589 * or blocking I/O operations.
2591 * We need to pin the memory or block GC.
2593 static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray jarr, jboolean* isCopy) {
2594 ScopedJniThreadState ts(env);
2595 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2596 pinPrimitiveArray(arrayObj);
2597 void* data = arrayObj->contents;
2598 if (UNLIKELY(isCopy != NULL)) {
2599 *isCopy = JNI_FALSE;
2605 * Release an array obtained with GetPrimitiveArrayCritical.
2607 static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray jarr, void* carray, jint mode) {
2608 if (mode != JNI_COMMIT) {
2609 ScopedJniThreadState ts(env);
2610 ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2611 unpinPrimitiveArray(arrayObj);
2616 * Like GetStringChars, but with restricted use.
2618 static const jchar* GetStringCritical(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2619 ScopedJniThreadState ts(env);
2621 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2622 ArrayObject* strChars = strObj->array();
2624 pinPrimitiveArray(strChars);
2626 const u2* data = strObj->chars();
2627 if (isCopy != NULL) {
2628 *isCopy = JNI_FALSE;
2630 return (jchar*) data;
2634 * Like ReleaseStringChars, but with restricted use.
2636 static void ReleaseStringCritical(JNIEnv* env, jstring jstr, const jchar* carray) {
2637 ScopedJniThreadState ts(env);
2638 StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2639 ArrayObject* strChars = strObj->array();
2640 unpinPrimitiveArray(strChars);
2644 * Create a new weak global reference.
2646 static jweak NewWeakGlobalRef(JNIEnv* env, jobject jobj) {
2647 ScopedJniThreadState ts(env);
2648 Object *obj = dvmDecodeIndirectRef(ts.self(), jobj);
2649 return (jweak) addWeakGlobalReference(obj);
2653 * Delete the specified weak global reference.
2655 static void DeleteWeakGlobalRef(JNIEnv* env, jweak wref) {
2656 ScopedJniThreadState ts(env);
2657 deleteWeakGlobalReference(wref);
2661 * Quick check for pending exceptions.
2663 * TODO: we should be able to skip the enter/exit macros here.
2665 static jboolean ExceptionCheck(JNIEnv* env) {
2666 ScopedJniThreadState ts(env);
2667 return dvmCheckException(ts.self());
2671 * Returns the type of the object referred to by "obj". It can be local,
2672 * global, or weak global.
2674 * In the current implementation, references can be global and local at
2675 * the same time, so while the return value is accurate it may not tell
2678 static jobjectRefType GetObjectRefType(JNIEnv* env, jobject jobj) {
2679 ScopedJniThreadState ts(env);
2680 return dvmGetJNIRefType(ts.self(), jobj);
2684 * Allocate and return a new java.nio.ByteBuffer for this block of memory.
2686 static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
2687 ScopedJniThreadState ts(env);
2690 ALOGE("JNI ERROR (app bug): negative buffer capacity: %lld", capacity);
2693 if (address == NULL && capacity != 0) {
2694 ALOGE("JNI ERROR (app bug): non-zero capacity for NULL pointer: %lld", capacity);
2698 /* create an instance of java.nio.DirectByteBuffer */
2699 ClassObject* bufferClazz = gDvm.classJavaNioDirectByteBuffer;
2700 if (!dvmIsClassInitialized(bufferClazz) && !dvmInitClass(bufferClazz)) {
2703 Object* newObj = dvmAllocObject(bufferClazz, ALLOC_DONT_TRACK);
2704 if (newObj == NULL) {
2707 /* call the constructor */
2708 jobject result = addLocalReference(ts.self(), newObj);
2710 dvmCallMethod(ts.self(), gDvm.methJavaNioDirectByteBuffer_init,
2711 newObj, &unused, (jlong) address, (jint) capacity);
2712 if (dvmGetException(ts.self()) != NULL) {
2713 deleteLocalReference(ts.self(), result);
2720 * Get the starting address of the buffer for the specified java.nio.Buffer.
2722 * If this is not a "direct" buffer, we return NULL.
2724 static void* GetDirectBufferAddress(JNIEnv* env, jobject jbuf) {
2725 ScopedJniThreadState ts(env);
2727 // All Buffer objects have an effectiveDirectAddress field.
2728 Object* bufObj = dvmDecodeIndirectRef(ts.self(), jbuf);
2729 return (void*) dvmGetFieldLong(bufObj, gDvm.offJavaNioBuffer_effectiveDirectAddress);
2733 * Get the capacity of the buffer for the specified java.nio.Buffer.
2735 * Returns -1 if the object is not a direct buffer. (We actually skip
2736 * this check, since it's expensive to determine, and just return the
2737 * capacity regardless.)
2739 static jlong GetDirectBufferCapacity(JNIEnv* env, jobject jbuf) {
2740 ScopedJniThreadState ts(env);
2743 * The capacity is always in the Buffer.capacity field.
2745 * (The "check" version should verify that this is actually a Buffer,
2746 * but we're not required to do so here.)
2748 Object* buf = dvmDecodeIndirectRef(ts.self(), jbuf);
2749 return dvmGetFieldInt(buf, gDvm.offJavaNioBuffer_capacity);
2754 * ===========================================================================
2755 * JNI invocation functions
2756 * ===========================================================================
2760 * Handle AttachCurrentThread{AsDaemon}.
2762 * We need to make sure the VM is actually running. For example, if we start
2763 * up, issue an Attach, and the VM exits almost immediately, by the time the
2764 * attaching happens the VM could already be shutting down.
2766 * It's hard to avoid a race condition here because we don't want to hold
2767 * a lock across the entire operation. What we can do is temporarily
2768 * increment the thread count to prevent a VM exit.
2770 * This could potentially still have problems if a daemon thread calls here
2771 * while the VM is shutting down. dvmThreadSelf() will work, since it just
2772 * uses pthread TLS, but dereferencing "vm" could fail. Such is life when
2773 * you shut down a VM while threads are still running inside it.
2775 * Remember that some code may call this as a way to find the per-thread
2776 * JNIEnv pointer. Don't do excess work for that case.
2778 static jint attachThread(JavaVM* vm, JNIEnv** p_env, void* thr_args, bool isDaemon) {
2779 JavaVMAttachArgs* args = (JavaVMAttachArgs*) thr_args;
2782 * Return immediately if we're already one with the VM.
2784 Thread* self = dvmThreadSelf();
2786 *p_env = self->jniEnv;
2791 * No threads allowed in zygote mode.
2797 /* increment the count to keep the VM from bailing while we run */
2798 dvmLockThreadList(NULL);
2799 if (gDvm.nonDaemonThreadCount == 0) {
2801 ALOGV("Refusing to attach thread '%s' -- VM is shutting down",
2802 (thr_args == NULL) ? "(unknown)" : args->name);
2803 dvmUnlockThreadList();
2806 gDvm.nonDaemonThreadCount++;
2807 dvmUnlockThreadList();
2809 /* tweak the JavaVMAttachArgs as needed */
2810 JavaVMAttachArgs argsCopy;
2812 /* allow the v1.1 calling convention */
2813 argsCopy.version = JNI_VERSION_1_2;
2814 argsCopy.name = NULL;
2815 argsCopy.group = (jobject) dvmGetMainThreadGroup();
2817 argsCopy.version = args->version;
2818 argsCopy.name = args->name;
2819 if (args->group != NULL) {
2820 argsCopy.group = (jobject) dvmDecodeIndirectRef(NULL, args->group);
2822 argsCopy.group = (jobject) dvmGetMainThreadGroup();
2826 bool result = dvmAttachCurrentThread(&argsCopy, isDaemon);
2828 /* restore the count */
2829 dvmLockThreadList(NULL);
2830 gDvm.nonDaemonThreadCount--;
2831 dvmUnlockThreadList();
2834 * Change the status to indicate that we're out in native code. This
2835 * call is not guarded with state-change macros, so we have to do it
2839 self = dvmThreadSelf();
2840 assert(self != NULL);
2841 dvmChangeStatus(self, THREAD_NATIVE);
2842 *p_env = self->jniEnv;
2850 * Attach the current thread to the VM. If the thread is already attached,
2853 static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
2854 return attachThread(vm, p_env, thr_args, false);
2858 * Like AttachCurrentThread, but set the "daemon" flag.
2860 static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args)
2862 return attachThread(vm, p_env, thr_args, true);
2866 * Dissociate the current thread from the VM.
2868 static jint DetachCurrentThread(JavaVM* vm) {
2869 Thread* self = dvmThreadSelf();
2871 /* not attached, can't do anything */
2875 /* switch to "running" to check for suspension */
2876 dvmChangeStatus(self, THREAD_RUNNING);
2878 /* detach the thread */
2879 dvmDetachCurrentThread();
2881 /* (no need to change status back -- we have no status) */
2886 * If current thread is attached to VM, return the associated JNIEnv.
2887 * Otherwise, stuff NULL in and return JNI_EDETACHED.
2889 * JVMTI overloads this by specifying a magic value for "version", so we
2890 * do want to check that here.
2892 static jint GetEnv(JavaVM* vm, void** env, jint version) {
2893 Thread* self = dvmThreadSelf();
2895 if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6) {
2896 return JNI_EVERSION;
2902 /* TODO: status change is probably unnecessary */
2903 dvmChangeStatus(self, THREAD_RUNNING);
2904 *env = (void*) dvmGetThreadJNIEnv(self);
2905 dvmChangeStatus(self, THREAD_NATIVE);
2907 return (*env != NULL) ? JNI_OK : JNI_EDETACHED;
2911 * Destroy the VM. This may be called from any thread.
2913 * If the current thread is attached, wait until the current thread is
2914 * the only non-daemon user-level thread. If the current thread is not
2915 * attached, we attach it and do the processing as usual. (If the attach
2916 * fails, it's probably because all the non-daemon threads have already
2917 * exited and the VM doesn't want to let us back in.)
2919 * TODO: we don't really deal with the situation where more than one thread
2920 * has called here. One thread wins, the other stays trapped waiting on
2921 * the condition variable forever. Not sure this situation is interesting
2924 static jint DestroyJavaVM(JavaVM* vm) {
2925 JavaVMExt* ext = (JavaVMExt*) vm;
2930 if (gDvm.verboseShutdown) {
2931 ALOGD("DestroyJavaVM waiting for non-daemon threads to exit");
2935 * Sleep on a condition variable until it's okay to exit.
2937 Thread* self = dvmThreadSelf();
2940 if (AttachCurrentThread(vm, &tmpEnv, NULL) != JNI_OK) {
2941 ALOGV("Unable to reattach main for Destroy; assuming VM is shutting down (count=%d)",
2942 gDvm.nonDaemonThreadCount);
2945 ALOGV("Attached to wait for shutdown in Destroy");
2948 dvmChangeStatus(self, THREAD_VMWAIT);
2950 dvmLockThreadList(self);
2951 gDvm.nonDaemonThreadCount--; // remove current thread from count
2953 while (gDvm.nonDaemonThreadCount > 0) {
2954 pthread_cond_wait(&gDvm.vmExitCond, &gDvm.threadListLock);
2957 dvmUnlockThreadList();
2961 // TODO: call System.exit() to run any registered shutdown hooks
2962 // (this may not return -- figure out how this should work)
2964 if (gDvm.verboseShutdown) {
2965 ALOGD("DestroyJavaVM shutting VM down");
2969 // TODO - free resources associated with JNI-attached daemon threads
2978 * ===========================================================================
2980 * ===========================================================================
2983 static const struct JNINativeInterface gNativeInterface = {
2994 FromReflectedMethod,
3018 EnsureLocalCapacity,
3061 CallNonvirtualObjectMethod,
3062 CallNonvirtualObjectMethodV,
3063 CallNonvirtualObjectMethodA,
3064 CallNonvirtualBooleanMethod,
3065 CallNonvirtualBooleanMethodV,
3066 CallNonvirtualBooleanMethodA,
3067 CallNonvirtualByteMethod,
3068 CallNonvirtualByteMethodV,
3069 CallNonvirtualByteMethodA,
3070 CallNonvirtualCharMethod,
3071 CallNonvirtualCharMethodV,
3072 CallNonvirtualCharMethodA,
3073 CallNonvirtualShortMethod,
3074 CallNonvirtualShortMethodV,
3075 CallNonvirtualShortMethodA,
3076 CallNonvirtualIntMethod,
3077 CallNonvirtualIntMethodV,
3078 CallNonvirtualIntMethodA,
3079 CallNonvirtualLongMethod,
3080 CallNonvirtualLongMethodV,
3081 CallNonvirtualLongMethodA,
3082 CallNonvirtualFloatMethod,
3083 CallNonvirtualFloatMethodV,
3084 CallNonvirtualFloatMethodA,
3085 CallNonvirtualDoubleMethod,
3086 CallNonvirtualDoubleMethodV,
3087 CallNonvirtualDoubleMethodA,
3088 CallNonvirtualVoidMethod,
3089 CallNonvirtualVoidMethodV,
3090 CallNonvirtualVoidMethodA,
3115 CallStaticObjectMethod,
3116 CallStaticObjectMethodV,
3117 CallStaticObjectMethodA,
3118 CallStaticBooleanMethod,
3119 CallStaticBooleanMethodV,
3120 CallStaticBooleanMethodA,
3121 CallStaticByteMethod,
3122 CallStaticByteMethodV,
3123 CallStaticByteMethodA,
3124 CallStaticCharMethod,
3125 CallStaticCharMethodV,
3126 CallStaticCharMethodA,
3127 CallStaticShortMethod,
3128 CallStaticShortMethodV,
3129 CallStaticShortMethodA,
3130 CallStaticIntMethod,
3131 CallStaticIntMethodV,
3132 CallStaticIntMethodA,
3133 CallStaticLongMethod,
3134 CallStaticLongMethodV,
3135 CallStaticLongMethodA,
3136 CallStaticFloatMethod,
3137 CallStaticFloatMethodV,
3138 CallStaticFloatMethodA,
3139 CallStaticDoubleMethod,
3140 CallStaticDoubleMethodV,
3141 CallStaticDoubleMethodA,
3142 CallStaticVoidMethod,
3143 CallStaticVoidMethodV,
3144 CallStaticVoidMethodA,
3148 GetStaticObjectField,
3149 GetStaticBooleanField,
3152 GetStaticShortField,
3155 GetStaticFloatField,
3156 GetStaticDoubleField,
3158 SetStaticObjectField,
3159 SetStaticBooleanField,
3162 SetStaticShortField,
3165 SetStaticFloatField,
3166 SetStaticDoubleField,
3177 ReleaseStringUTFChars,
3181 GetObjectArrayElement,
3182 SetObjectArrayElement,
3193 GetBooleanArrayElements,
3194 GetByteArrayElements,
3195 GetCharArrayElements,
3196 GetShortArrayElements,
3197 GetIntArrayElements,
3198 GetLongArrayElements,
3199 GetFloatArrayElements,
3200 GetDoubleArrayElements,
3202 ReleaseBooleanArrayElements,
3203 ReleaseByteArrayElements,
3204 ReleaseCharArrayElements,
3205 ReleaseShortArrayElements,
3206 ReleaseIntArrayElements,
3207 ReleaseLongArrayElements,
3208 ReleaseFloatArrayElements,
3209 ReleaseDoubleArrayElements,
3211 GetBooleanArrayRegion,
3214 GetShortArrayRegion,
3217 GetFloatArrayRegion,
3218 GetDoubleArrayRegion,
3219 SetBooleanArrayRegion,
3222 SetShortArrayRegion,
3225 SetFloatArrayRegion,
3226 SetDoubleArrayRegion,
3239 GetPrimitiveArrayCritical,
3240 ReleasePrimitiveArrayCritical,
3243 ReleaseStringCritical,
3246 DeleteWeakGlobalRef,
3250 NewDirectByteBuffer,
3251 GetDirectBufferAddress,
3252 GetDirectBufferCapacity,
3257 static const struct JNIInvokeInterface gInvokeInterface = {
3263 AttachCurrentThread,
3264 DetachCurrentThread,
3268 AttachCurrentThreadAsDaemon,
3272 * ===========================================================================
3274 * ===========================================================================
3278 * Create a new JNIEnv struct and add it to the VM's list.
3280 * "self" will be NULL for the main thread, since the VM hasn't started
3281 * yet; the value will be filled in later.
3283 JNIEnv* dvmCreateJNIEnv(Thread* self) {
3284 JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
3287 // ALOGI("Ent CreateJNIEnv: threadid=%d %p", self->threadId, self);
3291 JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
3292 newEnv->funcTable = &gNativeInterface;
3294 dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
3295 assert(newEnv->envThreadId != 0);
3297 /* make it obvious if we fail to initialize these later */
3298 newEnv->envThreadId = 0x77777775;
3299 newEnv->self = (Thread*) 0x77777779;
3301 if (gDvmJni.useCheckJni) {
3302 dvmUseCheckedJniEnv(newEnv);
3305 ScopedPthreadMutexLock lock(&vm->envListLock);
3307 /* insert at head of list */
3308 newEnv->next = vm->envList;
3309 assert(newEnv->prev == NULL);
3310 if (vm->envList == NULL) {
3311 // rare, but possible
3312 vm->envList = newEnv;
3314 vm->envList->prev = newEnv;
3316 vm->envList = newEnv;
3319 // ALOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self);
3320 return (JNIEnv*) newEnv;
3324 * Remove a JNIEnv struct from the list and free it.
3326 void dvmDestroyJNIEnv(JNIEnv* env) {
3331 //ALOGI("Ent DestroyJNIEnv: threadid=%d %p", self->threadId, self);
3333 JNIEnvExt* extEnv = (JNIEnvExt*) env;
3334 JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
3336 ScopedPthreadMutexLock lock(&vm->envListLock);
3338 if (extEnv == vm->envList) {
3339 assert(extEnv->prev == NULL);
3340 vm->envList = extEnv->next;
3342 assert(extEnv->prev != NULL);
3343 extEnv->prev->next = extEnv->next;
3345 if (extEnv->next != NULL) {
3346 extEnv->next->prev = extEnv->prev;
3350 //ALOGI("Xit DestroyJNIEnv: threadid=%d %p", self->threadId, self);
3354 * Enable "checked JNI" after the VM has partially started. This must
3355 * only be called in "zygote" mode, when we have one thread running.
3357 * This doesn't attempt to rewrite the JNI call bridge associated with
3358 * native methods, so we won't get those checks for any methods that have
3359 * already been resolved.
3361 void dvmLateEnableCheckedJni() {
3362 JNIEnvExt* extEnv = dvmGetJNIEnvForThread();
3363 if (extEnv == NULL) {
3364 ALOGE("dvmLateEnableCheckedJni: thread has no JNIEnv");
3367 JavaVMExt* extVm = (JavaVMExt*) gDvmJni.jniVm;
3368 assert(extVm != NULL);
3370 if (!gDvmJni.useCheckJni) {
3371 ALOGD("Late-enabling CheckJNI");
3372 dvmUseCheckedJniVm(extVm);
3373 dvmUseCheckedJniEnv(extEnv);
3375 ALOGD("Not late-enabling CheckJNI (already on)");
3382 jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
3387 * Return a buffer full of created VMs.
3389 * We always have zero or one.
3391 jint JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs) {
3392 if (gDvmJni.jniVm != NULL) {
3395 *vmBuf++ = gDvmJni.jniVm;
3404 * Create a new VM instance.
3406 * The current thread becomes the main VM thread. We return immediately,
3407 * which effectively means the caller is executing in a native method.
3409 jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
3410 const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args;
3411 if (args->version < JNI_VERSION_1_2) {
3412 return JNI_EVERSION;
3415 // TODO: don't allow creation of multiple VMs -- one per customer for now
3417 /* zero globals; not strictly necessary the first time a VM is started */
3418 memset(&gDvm, 0, sizeof(gDvm));
3421 * Set up structures for JNIEnv and VM.
3423 JavaVMExt* pVM = (JavaVMExt*) calloc(1, sizeof(JavaVMExt));
3424 pVM->funcTable = &gInvokeInterface;
3425 pVM->envList = NULL;
3426 dvmInitMutex(&pVM->envListLock);
3428 UniquePtr<const char*[]> argv(new const char*[args->nOptions]);
3429 memset(argv.get(), 0, sizeof(char*) * (args->nOptions));
3432 * Convert JNI args to argv.
3434 * We have to pull out vfprintf/exit/abort, because they use the
3435 * "extraInfo" field to pass function pointer "hooks" in. We also
3436 * look for the -Xcheck:jni stuff here.
3439 for (int i = 0; i < args->nOptions; i++) {
3440 const char* optStr = args->options[i].optionString;
3441 if (optStr == NULL) {
3442 dvmFprintf(stderr, "ERROR: CreateJavaVM failed: argument %d was NULL\n", i);
3444 } else if (strcmp(optStr, "vfprintf") == 0) {
3445 gDvm.vfprintfHook = (int (*)(FILE *, const char*, va_list))args->options[i].extraInfo;
3446 } else if (strcmp(optStr, "exit") == 0) {
3447 gDvm.exitHook = (void (*)(int)) args->options[i].extraInfo;
3448 } else if (strcmp(optStr, "abort") == 0) {
3449 gDvm.abortHook = (void (*)(void))args->options[i].extraInfo;
3450 } else if (strcmp(optStr, "sensitiveThread") == 0) {
3451 gDvm.isSensitiveThreadHook = (bool (*)(void))args->options[i].extraInfo;
3452 } else if (strcmp(optStr, "-Xcheck:jni") == 0) {
3453 gDvmJni.useCheckJni = true;
3454 } else if (strncmp(optStr, "-Xjniopts:", 10) == 0) {
3455 char* jniOpts = strdup(optStr + 10);
3456 size_t jniOptCount = 1;
3457 for (char* p = jniOpts; *p != 0; ++p) {
3463 char* jniOpt = jniOpts;
3464 for (size_t i = 0; i < jniOptCount; ++i) {
3465 if (strcmp(jniOpt, "warnonly") == 0) {
3466 gDvmJni.warnOnly = true;
3467 } else if (strcmp(jniOpt, "forcecopy") == 0) {
3468 gDvmJni.forceCopy = true;
3469 } else if (strcmp(jniOpt, "logThirdPartyJni") == 0) {
3470 gDvmJni.logThirdPartyJni = true;
3472 dvmFprintf(stderr, "ERROR: CreateJavaVM failed: unknown -Xjniopts option '%s'\n",
3478 jniOpt += strlen(jniOpt) + 1;
3482 /* regular option */
3483 argv[argc++] = optStr;
3487 if (gDvmJni.useCheckJni) {
3488 dvmUseCheckedJniVm(pVM);
3491 if (gDvmJni.jniVm != NULL) {
3492 dvmFprintf(stderr, "ERROR: Dalvik only supports one VM per process\n");
3496 gDvmJni.jniVm = (JavaVM*) pVM;
3499 * Create a JNIEnv for the main thread. We need to have something set up
3500 * here because some of the class initialization we do when starting
3501 * up the VM will call into native code.
3503 JNIEnvExt* pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);
3505 /* Initialize VM. */
3506 gDvm.initializing = true;
3507 std::string status =
3508 dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);
3509 gDvm.initializing = false;
3511 if (!status.empty()) {
3514 ALOGW("CreateJavaVM failed: %s", status.c_str());
3519 * Success! Return stuff to caller.
3521 dvmChangeStatus(NULL, THREAD_NATIVE);
3522 *p_env = (JNIEnv*) pEnv;
3523 *p_vm = (JavaVM*) pVM;
3524 ALOGV("CreateJavaVM succeeded");