1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
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
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17/*
18 * Dalvik implementation of JNI interfaces.
19 */
20#include "Dalvik.h"
21#include "JniInternal.h"
22#include "Misc.h"
23#include "ScopedPthreadMutexLock.h"
24#include "UniquePtr.h"
25
26#include <stdlib.h>
27#include <stdarg.h>
28#include <limits.h>
29
30/*
31Native methods and interaction with the GC
32
33All JNI methods must start by changing their thread status to
34THREAD_RUNNING, and finish by changing it back to THREAD_NATIVE before
35returning to native code.  The switch to "running" triggers a thread
36suspension check.
37
38With a rudimentary GC we should be able to skip the status change for
39simple functions, e.g.  IsSameObject, GetJavaVM, GetStringLength, maybe
40even access to fields with primitive types.  Our options are more limited
41with a compacting GC.
42
43For performance reasons we do as little error-checking as possible here.
44For example, we don't check to make sure the correct type of Object is
45passed in when setting a field, and we don't prevent you from storing
46new values in a "final" field.  Such things are best handled in the
47"check" version.  For actions that are common, dangerous, and must be
48checked at runtime, such as array bounds checks, we do the tests here.
49
50
51General notes on local/global reference tracking
52
53JNI provides explicit control over natively-held references that the GC
54needs to know about.  These can be local, in which case they're released
55when the native method returns into the VM, or global, which are held
56until explicitly released.  (There are also weak-global references,
57which have the lifespan and visibility of global references, but the
58object they refer to may be collected.)
59
60The references can be created with explicit JNI NewLocalRef / NewGlobalRef
61calls.  The former is very unusual, the latter is reasonably common
62(e.g. for caching references to class objects).
63
64Local references are most often created as a side-effect of JNI functions.
65For example, the AllocObject/NewObject functions must create local
66references to the objects returned, because nothing else in the GC root
67set has a reference to the new objects.
68
69The most common mode of operation is for a method to create zero or
70more local references and return.  Explicit "local delete" operations
71are expected to be exceedingly rare, except when walking through an
72object array, and the Push/PopLocalFrame calls are expected to be used
73infrequently.  For efficient operation, we want to add new local refs
74with a simple store/increment operation; to avoid infinite growth in
75pathological situations, we need to reclaim the space used by deleted
76entries.
77
78If we just want to maintain a list for the GC root set, we can use an
79expanding append-only array that compacts when objects are deleted.
80In typical situations, e.g. running through an array of objects, we will
81be deleting one of the most recently added entries, so we can minimize
82the number of elements moved (or avoid having to move any).
83
84If we want to conceal the pointer values from native code, which is
85necessary to allow the GC to move JNI-referenced objects around, then we
86have to use a more complicated indirection mechanism.
87
88The spec says, "Local references are only valid in the thread in which
89they are created.  The native code must not pass local references from
90one thread to another."
91
92
93Pinned objects
94
95For some large chunks of data, notably primitive arrays and String data,
96JNI allows the VM to choose whether it wants to pin the array object or
97make a copy.  We currently pin the memory for better execution performance.
98
99TODO: we're using simple root set references to pin primitive array data,
100because they have the property we need (i.e. the pointer we return is
101guaranteed valid until we explicitly release it).  However, if we have a
102compacting GC and don't want to pin all memory held by all global refs,
103we need to treat these differently.
104
105
106Global reference tracking
107
108There should be a small "active" set centered around the most-recently
109added items.
110
111Because it's global, access to it has to be synchronized.  Additions and
112removals require grabbing a mutex.  If the table serves as an indirection
113mechanism (i.e. it's not just a list for the benefit of the garbage
114collector), reference lookups may also require grabbing a mutex.
115
116The JNI spec does not define any sort of limit, so the list must be able
117to expand to a reasonable size.  It may be useful to log significant
118increases in usage to help identify resource leaks.
119
120
121Weak-global reference tracking
122
123[TBD]
124
125
126Local reference tracking
127
128Each Thread/JNIEnv points to an IndirectRefTable.
129
130We implement Push/PopLocalFrame with actual stack frames.  Before a JNI
131frame gets popped, we set "nextEntry" to the "top" pointer of the current
132frame, effectively releasing the references.
133
134The GC will scan all references in the table.
135
136*/
137
138static void ReportJniError() {
139    dvmDumpThread(dvmThreadSelf(), false);
140    dvmAbort();
141}
142
143#ifdef WITH_JNI_STACK_CHECK
144# define COMPUTE_STACK_SUM(_self)   computeStackSum(_self);
145# define CHECK_STACK_SUM(_self)     checkStackSum(_self);
146
147/*
148 * Compute a CRC on the entire interpreted stack.
149 *
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).
152 */
153static void computeStackSum(Thread* self) {
154    const u1* low = (const u1*)SAVEAREA_FROM_FP(self->interpSave.curFrame);
155    u4 crc = dvmInitCrc32();
156    self->stackCrc = 0;
157    crc = dvmComputeCrc32(crc, low, self->interpStackStart - low);
158    self->stackCrc = crc;
159}
160
161/*
162 * Compute a CRC on the entire interpreted stack, and compare it to what
163 * we previously computed.
164 *
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.
170 */
171static void checkStackSum(Thread* self) {
172    const u1* low = (const u1*)SAVEAREA_FROM_FP(self->interpSave.curFrame);
173    u4 stackCrc = self->stackCrc;
174    self->stackCrc = 0;
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);
184        } else {
185            ALOGW("JNI: bad stack CRC (%08x vs %08x)", crc, stackCrc);
186            ReportJniError();
187        }
188    }
189    self->stackCrc = (u4) -1;       /* make logic errors more noticeable */
190}
191
192#else
193# define COMPUTE_STACK_SUM(_self)   ((void)0)
194# define CHECK_STACK_SUM(_self)     ((void)0)
195#endif
196
197
198/*
199 * ===========================================================================
200 *      Utility functions
201 * ===========================================================================
202 */
203
204/*
205 * Entry/exit processing for all JNI calls.
206 *
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.
212 */
213class ScopedJniThreadState {
214public:
215    explicit ScopedJniThreadState(JNIEnv* env) {
216        mSelf = ((JNIEnvExt*) env)->self;
217
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;
222            if (self != mSelf) {
223                ALOGE("JNI ERROR: env->self != thread-self (%p vs. %p); auto-correcting", mSelf, self);
224                mSelf = self;
225            }
226        }
227
228        CHECK_STACK_SUM(mSelf);
229        dvmChangeStatus(mSelf, THREAD_RUNNING);
230    }
231
232    ~ScopedJniThreadState() {
233        dvmChangeStatus(mSelf, THREAD_NATIVE);
234        COMPUTE_STACK_SUM(mSelf);
235    }
236
237    inline Thread* self() {
238        return mSelf;
239    }
240
241private:
242    Thread* mSelf;
243
244    // Disallow copy and assignment.
245    ScopedJniThreadState(const ScopedJniThreadState&);
246    void operator=(const ScopedJniThreadState&);
247};
248
249#define kGlobalRefsTableInitialSize 512
250#define kGlobalRefsTableMaxSize     51200       /* arbitrary, must be < 64K */
251
252#define kWeakGlobalRefsTableInitialSize 16
253
254#define kPinTableInitialSize        16
255#define kPinTableMaxSize            1024
256#define kPinComplainThreshold       10
257
258bool dvmJniStartup() {
259    if (!gDvm.jniGlobalRefTable.init(kGlobalRefsTableInitialSize,
260                                 kGlobalRefsTableMaxSize,
261                                 kIndirectKindGlobal)) {
262        return false;
263    }
264    if (!gDvm.jniWeakGlobalRefTable.init(kWeakGlobalRefsTableInitialSize,
265                                 kGlobalRefsTableMaxSize,
266                                 kIndirectKindWeakGlobal)) {
267        return false;
268    }
269
270    dvmInitMutex(&gDvm.jniGlobalRefLock);
271    dvmInitMutex(&gDvm.jniWeakGlobalRefLock);
272
273    if (!dvmInitReferenceTable(&gDvm.jniPinRefTable, kPinTableInitialSize, kPinTableMaxSize)) {
274        return false;
275    }
276
277    dvmInitMutex(&gDvm.jniPinRefLock);
278
279    return true;
280}
281
282void dvmJniShutdown() {
283    gDvm.jniGlobalRefTable.destroy();
284    gDvm.jniWeakGlobalRefTable.destroy();
285    dvmClearReferenceTable(&gDvm.jniPinRefTable);
286}
287
288bool dvmIsBadJniVersion(int version) {
289  // We don't support JNI_VERSION_1_1. These are the only other valid versions.
290  return version != JNI_VERSION_1_2 && version != JNI_VERSION_1_4 && version != JNI_VERSION_1_6;
291}
292
293/*
294 * Find the JNIEnv associated with the current thread.
295 *
296 * Currently stored in the Thread struct.  Could also just drop this into
297 * thread-local storage.
298 */
299JNIEnvExt* dvmGetJNIEnvForThread() {
300    Thread* self = dvmThreadSelf();
301    if (self == NULL) {
302        return NULL;
303    }
304    return (JNIEnvExt*) dvmGetThreadJNIEnv(self);
305}
306
307/*
308 * Convert an indirect reference to an Object reference.  The indirect
309 * reference may be local, global, or weak-global.
310 *
311 * If "jobj" is NULL, or is a weak global reference whose reference has
312 * been cleared, this returns NULL.  If jobj is an invalid indirect
313 * reference, kInvalidIndirectRefObject is returned.
314 *
315 * Note "env" may be NULL when decoding global references.
316 */
317Object* dvmDecodeIndirectRef(Thread* self, jobject jobj) {
318    if (jobj == NULL) {
319        return NULL;
320    }
321
322    switch (indirectRefKind(jobj)) {
323    case kIndirectKindLocal:
324        {
325            Object* result = self->jniLocalRefTable.get(jobj);
326            if (UNLIKELY(result == NULL)) {
327                ALOGE("JNI ERROR (app bug): use of deleted local reference (%p)", jobj);
328                ReportJniError();
329            }
330            return result;
331        }
332    case kIndirectKindGlobal:
333        {
334            // TODO: find a way to avoid the mutex activity here
335            IndirectRefTable* pRefTable = &gDvm.jniGlobalRefTable;
336            ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
337            Object* result = pRefTable->get(jobj);
338            if (UNLIKELY(result == NULL)) {
339                ALOGE("JNI ERROR (app bug): use of deleted global reference (%p)", jobj);
340                ReportJniError();
341            }
342            return result;
343        }
344    case kIndirectKindWeakGlobal:
345        {
346            // TODO: find a way to avoid the mutex activity here
347            IndirectRefTable* pRefTable = &gDvm.jniWeakGlobalRefTable;
348            ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
349            Object* result = pRefTable->get(jobj);
350            if (result == kClearedJniWeakGlobal) {
351                result = NULL;
352            } else if (UNLIKELY(result == NULL)) {
353                ALOGE("JNI ERROR (app bug): use of deleted weak global reference (%p)", jobj);
354                ReportJniError();
355            }
356            return result;
357        }
358    case kIndirectKindInvalid:
359    default:
360        if (UNLIKELY(gDvmJni.workAroundAppJniBugs)) {
361            // Assume an invalid local reference is actually a direct pointer.
362            return reinterpret_cast<Object*>(jobj);
363        }
364        ALOGW("Invalid indirect reference %p in decodeIndirectRef", jobj);
365        ReportJniError();
366        return kInvalidIndirectRefObject;
367    }
368}
369
370static void AddLocalReferenceFailure(IndirectRefTable* pRefTable) {
371    pRefTable->dump("JNI local");
372    ALOGE("Failed adding to JNI local ref table (has %zd entries)", pRefTable->capacity());
373    ReportJniError(); // spec says call FatalError; this is equivalent
374}
375
376/*
377 * Add a local reference for an object to the current stack frame.  When
378 * the native function returns, the reference will be discarded.
379 *
380 * We need to allow the same reference to be added multiple times.
381 *
382 * This will be called on otherwise unreferenced objects.  We cannot do
383 * GC allocations here, and it's best if we don't grab a mutex.
384 */
385static inline jobject addLocalReference(Thread* self, Object* obj) {
386    if (obj == NULL) {
387        return NULL;
388    }
389
390    IndirectRefTable* pRefTable = &self->jniLocalRefTable;
391    void* curFrame = self->interpSave.curFrame;
392    u4 cookie = SAVEAREA_FROM_FP(curFrame)->xtra.localRefCookie;
393    jobject jobj = (jobject) pRefTable->add(cookie, obj);
394    if (UNLIKELY(jobj == NULL)) {
395        AddLocalReferenceFailure(pRefTable);
396    }
397
398    if (UNLIKELY(gDvmJni.workAroundAppJniBugs)) {
399        // Hand out direct pointers to support broken old apps.
400        return reinterpret_cast<jobject>(obj);
401    }
402    return jobj;
403}
404
405/*
406 * Ensure that at least "capacity" references can be held in the local
407 * refs table of the current thread.
408 */
409static bool ensureLocalCapacity(Thread* self, int capacity) {
410    int numEntries = self->jniLocalRefTable.capacity();
411    // TODO: this isn't quite right, since "numEntries" includes holes
412    return ((kJniLocalRefMax - numEntries) >= capacity);
413}
414
415/*
416 * Explicitly delete a reference from the local list.
417 */
418static void deleteLocalReference(Thread* self, jobject jobj) {
419    if (jobj == NULL) {
420        return;
421    }
422
423    IndirectRefTable* pRefTable = &self->jniLocalRefTable;
424    void* curFrame = self->interpSave.curFrame;
425    u4 cookie = SAVEAREA_FROM_FP(curFrame)->xtra.localRefCookie;
426    if (!pRefTable->remove(cookie, jobj)) {
427        /*
428         * Attempting to delete a local reference that is not in the
429         * topmost local reference frame is a no-op.  DeleteLocalRef returns
430         * void and doesn't throw any exceptions, but we should probably
431         * complain about it so the user will notice that things aren't
432         * going quite the way they expect.
433         */
434        ALOGW("JNI WARNING: DeleteLocalRef(%p) failed to find entry", jobj);
435    }
436}
437
438/*
439 * Add a global reference for an object.
440 *
441 * We may add the same object more than once.  Add/remove calls are paired,
442 * so it needs to appear on the list multiple times.
443 */
444static jobject addGlobalReference(Object* obj) {
445    if (obj == NULL) {
446        return NULL;
447    }
448
449    //ALOGI("adding obj=%p", obj);
450    //dvmDumpThread(dvmThreadSelf(), false);
451
452    if (false && dvmIsClassObject((Object*)obj)) {
453        ClassObject* clazz = (ClassObject*) obj;
454        ALOGI("-------");
455        ALOGI("Adding global ref on class %s", clazz->descriptor);
456        dvmDumpThread(dvmThreadSelf(), false);
457    }
458    if (false && ((Object*)obj)->clazz == gDvm.classJavaLangString) {
459        StringObject* strObj = (StringObject*) obj;
460        char* str = dvmCreateCstrFromString(strObj);
461        if (strcmp(str, "sync-response") == 0) {
462            ALOGI("-------");
463            ALOGI("Adding global ref on string '%s'", str);
464            dvmDumpThread(dvmThreadSelf(), false);
465            //dvmAbort();
466        }
467        free(str);
468    }
469    if (false && ((Object*)obj)->clazz == gDvm.classArrayByte) {
470        ArrayObject* arrayObj = (ArrayObject*) obj;
471        if (arrayObj->length == 8192 /*&&
472            dvmReferenceTableEntries(&gDvm.jniGlobalRefTable) > 400*/)
473        {
474            ALOGI("Adding global ref on byte array %p (len=%d)",
475                arrayObj, arrayObj->length);
476            dvmDumpThread(dvmThreadSelf(), false);
477        }
478    }
479
480    ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
481
482    /*
483     * Throwing an exception on failure is problematic, because JNI code
484     * may not be expecting an exception, and things sort of cascade.  We
485     * want to have a hard limit to catch leaks during debugging, but this
486     * otherwise needs to expand until memory is consumed.  As a practical
487     * matter, if we have many thousands of global references, chances are
488     * we're either leaking global ref table entries or we're going to
489     * run out of space in the GC heap.
490     */
491    jobject jobj = (jobject) gDvm.jniGlobalRefTable.add(IRT_FIRST_SEGMENT, obj);
492    if (jobj == NULL) {
493        gDvm.jniGlobalRefTable.dump("JNI global");
494        ALOGE("Failed adding to JNI global ref table (%zd entries)",
495                gDvm.jniGlobalRefTable.capacity());
496        ReportJniError();
497    }
498
499    LOGVV("GREF add %p  (%s.%s)", obj,
500        dvmGetCurrentJNIMethod()->clazz->descriptor,
501        dvmGetCurrentJNIMethod()->name);
502
503    return jobj;
504}
505
506static jobject addWeakGlobalReference(Object* obj) {
507    if (obj == NULL) {
508        return NULL;
509    }
510
511    ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
512    IndirectRefTable *table = &gDvm.jniWeakGlobalRefTable;
513    jobject jobj = (jobject) table->add(IRT_FIRST_SEGMENT, obj);
514    if (jobj == NULL) {
515        gDvm.jniWeakGlobalRefTable.dump("JNI weak global");
516        ALOGE("Failed adding to JNI weak global ref table (%zd entries)", table->capacity());
517        ReportJniError();
518    }
519    return jobj;
520}
521
522static void deleteWeakGlobalReference(jobject jobj) {
523    if (jobj == NULL) {
524        return;
525    }
526
527    ScopedPthreadMutexLock lock(&gDvm.jniWeakGlobalRefLock);
528    IndirectRefTable *table = &gDvm.jniWeakGlobalRefTable;
529    if (!table->remove(IRT_FIRST_SEGMENT, jobj)) {
530        ALOGW("JNI: DeleteWeakGlobalRef(%p) failed to find entry", jobj);
531    }
532}
533
534/*
535 * Remove a global reference.  In most cases it's the entry most recently
536 * added, which makes this pretty quick.
537 *
538 * Thought: if it's not the most recent entry, just null it out.  When we
539 * fill up, do a compaction pass before we expand the list.
540 */
541static void deleteGlobalReference(jobject jobj) {
542    if (jobj == NULL) {
543        return;
544    }
545
546    ScopedPthreadMutexLock lock(&gDvm.jniGlobalRefLock);
547    if (!gDvm.jniGlobalRefTable.remove(IRT_FIRST_SEGMENT, jobj)) {
548        ALOGW("JNI: DeleteGlobalRef(%p) failed to find entry", jobj);
549        return;
550    }
551}
552
553/*
554 * Objects don't currently move, so we just need to create a reference
555 * that will ensure the array object isn't collected.
556 *
557 * We use a separate reference table, which is part of the GC root set.
558 */
559static void pinPrimitiveArray(ArrayObject* arrayObj) {
560    if (arrayObj == NULL) {
561        return;
562    }
563
564    ScopedPthreadMutexLock lock(&gDvm.jniPinRefLock);
565
566    if (!dvmAddToReferenceTable(&gDvm.jniPinRefTable, (Object*)arrayObj)) {
567        dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
568        ALOGE("Failed adding to JNI pinned array ref table (%d entries)",
569           (int) dvmReferenceTableEntries(&gDvm.jniPinRefTable));
570        ReportJniError();
571    }
572
573    /*
574     * The total number of pinned primitive arrays should be pretty small.
575     * A single array should not be pinned more than once or twice; any
576     * more than that is a strong indicator that a Release function is
577     * not being called.
578     */
579    int count = 0;
580    Object** ppObj = gDvm.jniPinRefTable.table;
581    while (ppObj < gDvm.jniPinRefTable.nextEntry) {
582        if (*ppObj++ == (Object*) arrayObj) {
583            count++;
584        }
585    }
586
587    if (count > kPinComplainThreshold) {
588        ALOGW("JNI: pin count on array %p (%s) is now %d",
589              arrayObj, arrayObj->clazz->descriptor, count);
590        /* keep going */
591    }
592}
593
594/*
595 * Un-pin the array object.  If an object was pinned twice, it must be
596 * unpinned twice before it's free to move.
597 */
598static void unpinPrimitiveArray(ArrayObject* arrayObj) {
599    if (arrayObj == NULL) {
600        return;
601    }
602
603    ScopedPthreadMutexLock lock(&gDvm.jniPinRefLock);
604    if (!dvmRemoveFromReferenceTable(&gDvm.jniPinRefTable,
605            gDvm.jniPinRefTable.table, (Object*) arrayObj))
606    {
607        ALOGW("JNI: unpinPrimitiveArray(%p) failed to find entry (valid=%d)",
608            arrayObj, dvmIsHeapAddress((Object*) arrayObj));
609        return;
610    }
611}
612
613/*
614 * Dump the contents of the JNI reference tables to the log file.
615 *
616 * We only dump the local refs associated with the current thread.
617 */
618void dvmDumpJniReferenceTables() {
619    Thread* self = dvmThreadSelf();
620    self->jniLocalRefTable.dump("JNI local");
621    gDvm.jniGlobalRefTable.dump("JNI global");
622    dvmDumpReferenceTable(&gDvm.jniPinRefTable, "JNI pinned array");
623}
624
625void dvmDumpJniStats(DebugOutputTarget* target) {
626    dvmPrintDebugMessage(target, "JNI: CheckJNI is %s", gDvmJni.useCheckJni ? "on" : "off");
627    if (gDvmJni.forceCopy) {
628        dvmPrintDebugMessage(target, " (with forcecopy)");
629    }
630    dvmPrintDebugMessage(target, "; workarounds are %s", gDvmJni.workAroundAppJniBugs ? "on" : "off");
631
632    dvmLockMutex(&gDvm.jniPinRefLock);
633    dvmPrintDebugMessage(target, "; pins=%d", dvmReferenceTableEntries(&gDvm.jniPinRefTable));
634    dvmUnlockMutex(&gDvm.jniPinRefLock);
635
636    dvmLockMutex(&gDvm.jniGlobalRefLock);
637    dvmPrintDebugMessage(target, "; globals=%d", gDvm.jniGlobalRefTable.capacity());
638    dvmUnlockMutex(&gDvm.jniGlobalRefLock);
639
640    dvmLockMutex(&gDvm.jniWeakGlobalRefLock);
641    size_t weaks = gDvm.jniWeakGlobalRefTable.capacity();
642    if (weaks > 0) {
643        dvmPrintDebugMessage(target, " (plus %d weak)", weaks);
644    }
645    dvmUnlockMutex(&gDvm.jniWeakGlobalRefLock);
646
647    dvmPrintDebugMessage(target, "\n\n");
648}
649
650/*
651 * Verify that a reference passed in from native code is one that the
652 * code is allowed to have.
653 *
654 * It's okay for native code to pass us a reference that:
655 *  - was passed in as an argument when invoked by native code (and hence
656 *    is in the JNI local refs table)
657 *  - was returned to it from JNI (and is now in the local refs table)
658 *  - is present in the JNI global refs table
659 *
660 * Used by -Xcheck:jni and GetObjectRefType.
661 */
662jobjectRefType dvmGetJNIRefType(Thread* self, jobject jobj) {
663    /*
664     * IndirectRefKind is currently defined as an exact match of
665     * jobjectRefType, so this is easy.  We have to decode it to determine
666     * if it's a valid reference and not merely valid-looking.
667     */
668    assert(jobj != NULL);
669
670    Object* obj = dvmDecodeIndirectRef(self, jobj);
671    if (obj == reinterpret_cast<Object*>(jobj) && gDvmJni.workAroundAppJniBugs) {
672        // If we're handing out direct pointers, check whether 'jobj' is a direct reference
673        // to a local reference.
674        return self->jniLocalRefTable.contains(obj) ? JNILocalRefType : JNIInvalidRefType;
675    } else if (obj == kInvalidIndirectRefObject) {
676        return JNIInvalidRefType;
677    } else {
678        return (jobjectRefType) indirectRefKind(jobj);
679    }
680}
681
682static void dumpMethods(Method* methods, size_t methodCount, const char* name) {
683    size_t i;
684    for (i = 0; i < methodCount; ++i) {
685        Method* method = &methods[i];
686        if (strcmp(name, method->name) == 0) {
687            char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
688            ALOGE("Candidate: %s.%s:%s", method->clazz->descriptor, name, desc);
689            free(desc);
690        }
691    }
692}
693
694static void dumpCandidateMethods(ClassObject* clazz, const char* methodName, const char* signature) {
695    ALOGE("ERROR: couldn't find native method");
696    ALOGE("Requested: %s.%s:%s", clazz->descriptor, methodName, signature);
697    dumpMethods(clazz->virtualMethods, clazz->virtualMethodCount, methodName);
698    dumpMethods(clazz->directMethods, clazz->directMethodCount, methodName);
699}
700
701static void throwNoSuchMethodError(ClassObject* c, const char* name, const char* sig, const char* kind) {
702    std::string msg(StringPrintf("no %s method \"%s.%s%s\"", kind, c->descriptor, name, sig));
703    dvmThrowNoSuchMethodError(msg.c_str());
704}
705
706/*
707 * Register a method that uses JNI calling conventions.
708 */
709static bool dvmRegisterJNIMethod(ClassObject* clazz, const char* methodName,
710    const char* signature, void* fnPtr)
711{
712    if (fnPtr == NULL) {
713        return false;
714    }
715
716    // If a signature starts with a '!', we take that as a sign that the native code doesn't
717    // need the extra JNI arguments (the JNIEnv* and the jclass).
718    bool fastJni = false;
719    if (*signature == '!') {
720        fastJni = true;
721        ++signature;
722        ALOGV("fast JNI method %s.%s:%s detected", clazz->descriptor, methodName, signature);
723    }
724
725    Method* method = dvmFindDirectMethodByDescriptor(clazz, methodName, signature);
726    if (method == NULL) {
727        method = dvmFindVirtualMethodByDescriptor(clazz, methodName, signature);
728    }
729    if (method == NULL) {
730        dumpCandidateMethods(clazz, methodName, signature);
731        throwNoSuchMethodError(clazz, methodName, signature, "static or non-static");
732        return false;
733    }
734
735    if (!dvmIsNativeMethod(method)) {
736        ALOGW("Unable to register: not native: %s.%s:%s", clazz->descriptor, methodName, signature);
737        throwNoSuchMethodError(clazz, methodName, signature, "native");
738        return false;
739    }
740
741    if (fastJni) {
742        // In this case, we have extra constraints to check...
743        if (dvmIsSynchronizedMethod(method)) {
744            // Synchronization is usually provided by the JNI bridge,
745            // but we won't have one.
746            ALOGE("fast JNI method %s.%s:%s cannot be synchronized",
747                    clazz->descriptor, methodName, signature);
748            return false;
749        }
750        if (!dvmIsStaticMethod(method)) {
751            // There's no real reason for this constraint, but since we won't
752            // be supplying a JNIEnv* or a jobject 'this', you're effectively
753            // static anyway, so it seems clearer to say so.
754            ALOGE("fast JNI method %s.%s:%s cannot be non-static",
755                    clazz->descriptor, methodName, signature);
756            return false;
757        }
758    }
759
760    if (method->nativeFunc != dvmResolveNativeMethod) {
761        /* this is allowed, but unusual */
762        ALOGV("Note: %s.%s:%s was already registered", clazz->descriptor, methodName, signature);
763    }
764
765    method->fastJni = fastJni;
766    dvmUseJNIBridge(method, fnPtr);
767
768    ALOGV("JNI-registered %s.%s:%s", clazz->descriptor, methodName, signature);
769    return true;
770}
771
772static const char* builtInPrefixes[] = {
773    "Landroid/",
774    "Lcom/android/",
775    "Lcom/google/android/",
776    "Ldalvik/",
777    "Ljava/",
778    "Ljavax/",
779    "Llibcore/",
780    "Lorg/apache/harmony/",
781};
782
783static bool shouldTrace(Method* method) {
784    const char* className = method->clazz->descriptor;
785    // Return true if the -Xjnitrace setting implies we should trace 'method'.
786    if (gDvm.jniTrace && strstr(className, gDvm.jniTrace)) {
787        return true;
788    }
789    // Return true if we're trying to log all third-party JNI activity and 'method' doesn't look
790    // like part of Android.
791    if (gDvmJni.logThirdPartyJni) {
792        for (size_t i = 0; i < NELEM(builtInPrefixes); ++i) {
793            if (strstr(className, builtInPrefixes[i]) == className) {
794                return false;
795            }
796        }
797        return true;
798    }
799    return false;
800}
801
802/*
803 * Point "method->nativeFunc" at the JNI bridge, and overload "method->insns"
804 * to point at the actual function.
805 */
806void dvmUseJNIBridge(Method* method, void* func) {
807    method->shouldTrace = shouldTrace(method);
808
809    // Does the method take any reference arguments?
810    method->noRef = true;
811    const char* cp = method->shorty;
812    while (*++cp != '\0') { // Pre-increment to skip return type.
813        if (*cp == 'L') {
814            method->noRef = false;
815            break;
816        }
817    }
818
819    DalvikBridgeFunc bridge = gDvmJni.useCheckJni ? dvmCheckCallJNIMethod : dvmCallJNIMethod;
820    dvmSetNativeFunc(method, bridge, (const u2*) func);
821}
822
823// TODO: rewrite this to share code with CheckJNI's tracing...
824static void appendValue(char type, const JValue value, char* buf, size_t n, bool appendComma)
825{
826    size_t len = strlen(buf);
827    if (len >= n - 32) { // 32 should be longer than anything we could append.
828        buf[len - 1] = '.';
829        buf[len - 2] = '.';
830        buf[len - 3] = '.';
831        return;
832    }
833    char* p = buf + len;
834    switch (type) {
835    case 'B':
836        if (value.b >= 0 && value.b < 10) {
837            sprintf(p, "%d", value.b);
838        } else {
839            sprintf(p, "%#x (%d)", value.b, value.b);
840        }
841        break;
842    case 'C':
843        if (value.c < 0x7f && value.c >= ' ') {
844            sprintf(p, "U+%x ('%c')", value.c, value.c);
845        } else {
846            sprintf(p, "U+%x", value.c);
847        }
848        break;
849    case 'D':
850        sprintf(p, "%g", value.d);
851        break;
852    case 'F':
853        sprintf(p, "%g", value.f);
854        break;
855    case 'I':
856        sprintf(p, "%d", value.i);
857        break;
858    case 'L':
859        sprintf(p, "%#x", value.i);
860        break;
861    case 'J':
862        sprintf(p, "%lld", value.j);
863        break;
864    case 'S':
865        sprintf(p, "%d", value.s);
866        break;
867    case 'V':
868        strcpy(p, "void");
869        break;
870    case 'Z':
871        strcpy(p, value.z ? "true" : "false");
872        break;
873    default:
874        sprintf(p, "unknown type '%c'", type);
875        break;
876    }
877
878    if (appendComma) {
879        strcat(p, ", ");
880    }
881}
882
883static void logNativeMethodEntry(const Method* method, const u4* args)
884{
885    char thisString[32] = { 0 };
886    const u4* sp = args;
887    if (!dvmIsStaticMethod(method)) {
888        sprintf(thisString, "this=0x%08x ", *sp++);
889    }
890
891    char argsString[128]= { 0 };
892    const char* desc = &method->shorty[1];
893    while (*desc != '\0') {
894        char argType = *desc++;
895        JValue value;
896        if (argType == 'D' || argType == 'J') {
897            value.j = dvmGetArgLong(sp, 0);
898            sp += 2;
899        } else {
900            value.i = *sp++;
901        }
902        appendValue(argType, value, argsString, sizeof(argsString),
903        *desc != '\0');
904    }
905
906    std::string className(dvmHumanReadableDescriptor(method->clazz->descriptor));
907    char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
908    ALOGI("-> %s %s%s %s(%s)", className.c_str(), method->name, signature, thisString, argsString);
909    free(signature);
910}
911
912static void logNativeMethodExit(const Method* method, Thread* self, const JValue returnValue)
913{
914    std::string className(dvmHumanReadableDescriptor(method->clazz->descriptor));
915    char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
916    if (dvmCheckException(self)) {
917        Object* exception = dvmGetException(self);
918        std::string exceptionClassName(dvmHumanReadableDescriptor(exception->clazz->descriptor));
919        ALOGI("<- %s %s%s threw %s", className.c_str(),
920                method->name, signature, exceptionClassName.c_str());
921    } else {
922        char returnValueString[128] = { 0 };
923        char returnType = method->shorty[0];
924        appendValue(returnType, returnValue, returnValueString, sizeof(returnValueString), false);
925        ALOGI("<- %s %s%s returned %s", className.c_str(),
926                method->name, signature, returnValueString);
927    }
928    free(signature);
929}
930
931/*
932 * Get the method currently being executed by examining the interp stack.
933 */
934const Method* dvmGetCurrentJNIMethod() {
935    assert(dvmThreadSelf() != NULL);
936
937    void* fp = dvmThreadSelf()->interpSave.curFrame;
938    const Method* meth = SAVEAREA_FROM_FP(fp)->method;
939
940    assert(meth != NULL);
941    assert(dvmIsNativeMethod(meth));
942    return meth;
943}
944
945/*
946 * Track a JNI MonitorEnter in the current thread.
947 *
948 * The goal is to be able to "implicitly" release all JNI-held monitors
949 * when the thread detaches.
950 *
951 * Monitors may be entered multiple times, so we add a new entry for each
952 * enter call.  It would be more efficient to keep a counter.  At present
953 * there's no real motivation to improve this however.
954 */
955static void trackMonitorEnter(Thread* self, Object* obj) {
956    static const int kInitialSize = 16;
957    ReferenceTable* refTable = &self->jniMonitorRefTable;
958
959    /* init table on first use */
960    if (refTable->table == NULL) {
961        assert(refTable->maxEntries == 0);
962
963        if (!dvmInitReferenceTable(refTable, kInitialSize, INT_MAX)) {
964            ALOGE("Unable to initialize monitor tracking table");
965            ReportJniError();
966        }
967    }
968
969    if (!dvmAddToReferenceTable(refTable, obj)) {
970        /* ran out of memory? could throw exception instead */
971        ALOGE("Unable to add entry to monitor tracking table");
972        ReportJniError();
973    } else {
974        LOGVV("--- added monitor %p", obj);
975    }
976}
977
978/*
979 * Track a JNI MonitorExit in the current thread.
980 */
981static void trackMonitorExit(Thread* self, Object* obj) {
982    ReferenceTable* pRefTable = &self->jniMonitorRefTable;
983
984    if (!dvmRemoveFromReferenceTable(pRefTable, pRefTable->table, obj)) {
985        ALOGE("JNI monitor %p not found in tracking list", obj);
986        /* keep going? */
987    } else {
988        LOGVV("--- removed monitor %p", obj);
989    }
990}
991
992/*
993 * Release all monitors held by the jniMonitorRefTable list.
994 */
995void dvmReleaseJniMonitors(Thread* self) {
996    ReferenceTable* pRefTable = &self->jniMonitorRefTable;
997    Object** top = pRefTable->table;
998
999    if (top == NULL) {
1000        return;
1001    }
1002    Object** ptr = pRefTable->nextEntry;
1003    while (--ptr >= top) {
1004        if (!dvmUnlockObject(self, *ptr)) {
1005            ALOGW("Unable to unlock monitor %p at thread detach", *ptr);
1006        } else {
1007            LOGVV("--- detach-releasing monitor %p", *ptr);
1008        }
1009    }
1010
1011    /* zap it */
1012    pRefTable->nextEntry = pRefTable->table;
1013}
1014
1015/*
1016 * Determine if the specified class can be instantiated from JNI.  This
1017 * is used by AllocObject / NewObject, which are documented as throwing
1018 * an exception for abstract and interface classes, and not accepting
1019 * array classes.  We also want to reject attempts to create new Class
1020 * objects, since only DefineClass should do that.
1021 */
1022static bool canAllocClass(ClassObject* clazz) {
1023    if (dvmIsAbstractClass(clazz) || dvmIsInterfaceClass(clazz)) {
1024        /* JNI spec defines what this throws */
1025        dvmThrowInstantiationException(clazz, "abstract class or interface");
1026        return false;
1027    } else if (dvmIsArrayClass(clazz) || dvmIsTheClassClass(clazz)) {
1028        /* spec says "must not" for arrays, ignores Class */
1029        dvmThrowInstantiationException(clazz, "wrong JNI function");
1030        return false;
1031    }
1032    return true;
1033}
1034
1035
1036/*
1037 * ===========================================================================
1038 *      JNI call bridge
1039 * ===========================================================================
1040 */
1041
1042/*
1043 * The functions here form a bridge between interpreted code and JNI native
1044 * functions.  The basic task is to convert an array of primitives and
1045 * references into C-style function arguments.  This is architecture-specific
1046 * and usually requires help from assembly code.
1047 *
1048 * The bridge takes four arguments: the array of parameters, a place to
1049 * store the function result (if any), the method to call, and a pointer
1050 * to the current thread.
1051 *
1052 * These functions aren't called directly from elsewhere in the VM.
1053 * A pointer in the Method struct points to one of these, and when a native
1054 * method is invoked the interpreter jumps to it.
1055 *
1056 * (The "internal native" methods are invoked the same way, but instead
1057 * of calling through a bridge, the target method is called directly.)
1058 *
1059 * The "args" array should not be modified, but we do so anyway for
1060 * performance reasons.  We know that it points to the "outs" area on
1061 * the current method's interpreted stack.  This area is ignored by the
1062 * precise GC, because there is no register map for a native method (for
1063 * an interpreted method the args would be listed in the argument set).
1064 * We know all of the values exist elsewhere on the interpreted stack,
1065 * because the method call setup copies them right before making the call,
1066 * so we don't have to worry about concealing stuff from the GC.
1067 *
1068 * If we don't want to modify "args", we either have to create a local
1069 * copy and modify it before calling dvmPlatformInvoke, or we have to do
1070 * the local reference replacement within dvmPlatformInvoke.  The latter
1071 * has some performance advantages, though if we can inline the local
1072 * reference adds we may win when there's a lot of reference args (unless
1073 * we want to code up some local ref table manipulation in assembly.
1074 */
1075
1076/*
1077 * If necessary, convert the value in pResult from a local/global reference
1078 * to an object pointer.
1079 *
1080 * If the returned reference is invalid, kInvalidIndirectRefObject will
1081 * be returned in pResult.
1082 */
1083static inline void convertReferenceResult(JNIEnv* env, JValue* pResult,
1084    const Method* method, Thread* self)
1085{
1086    if (method->shorty[0] == 'L' && !dvmCheckException(self) && pResult->l != NULL) {
1087        pResult->l = dvmDecodeIndirectRef(self, (jobject) pResult->l);
1088    }
1089}
1090
1091/*
1092 * General form, handles all cases.
1093 */
1094void dvmCallJNIMethod(const u4* args, JValue* pResult, const Method* method, Thread* self) {
1095    u4* modArgs = (u4*) args;
1096    jclass staticMethodClass = NULL;
1097
1098    u4 accessFlags = method->accessFlags;
1099    bool isSynchronized = (accessFlags & ACC_SYNCHRONIZED) != 0;
1100
1101    //ALOGI("JNI calling %p (%s.%s:%s):", method->insns,
1102    //    method->clazz->descriptor, method->name, method->shorty);
1103
1104    /*
1105     * Walk the argument list, creating local references for appropriate
1106     * arguments.
1107     */
1108    int idx = 0;
1109    Object* lockObj;
1110    if ((accessFlags & ACC_STATIC) != 0) {
1111        lockObj = (Object*) method->clazz;
1112        /* add the class object we pass in */
1113        staticMethodClass = (jclass) addLocalReference(self, (Object*) method->clazz);
1114    } else {
1115        lockObj = (Object*) args[0];
1116        /* add "this" */
1117        modArgs[idx++] = (u4) addLocalReference(self, (Object*) modArgs[0]);
1118    }
1119
1120    if (!method->noRef) {
1121        const char* shorty = &method->shorty[1];        /* skip return type */
1122        while (*shorty != '\0') {
1123            switch (*shorty++) {
1124            case 'L':
1125                //ALOGI("  local %d: 0x%08x", idx, modArgs[idx]);
1126                if (modArgs[idx] != 0) {
1127                    modArgs[idx] = (u4) addLocalReference(self, (Object*) modArgs[idx]);
1128                }
1129                break;
1130            case 'D':
1131            case 'J':
1132                idx++;
1133                break;
1134            default:
1135                /* Z B C S I -- do nothing */
1136                break;
1137            }
1138            idx++;
1139        }
1140    }
1141
1142    if (UNLIKELY(method->shouldTrace)) {
1143        logNativeMethodEntry(method, args);
1144    }
1145    if (UNLIKELY(isSynchronized)) {
1146        dvmLockObject(self, lockObj);
1147    }
1148
1149    ThreadStatus oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
1150
1151    ANDROID_MEMBAR_FULL();      /* guarantee ordering on method->insns */
1152    assert(method->insns != NULL);
1153
1154    JNIEnv* env = self->jniEnv;
1155    COMPUTE_STACK_SUM(self);
1156    dvmPlatformInvoke(env,
1157            (ClassObject*) staticMethodClass,
1158            method->jniArgInfo, method->insSize, modArgs, method->shorty,
1159            (void*) method->insns, pResult);
1160    CHECK_STACK_SUM(self);
1161
1162    dvmChangeStatus(self, oldStatus);
1163
1164    convertReferenceResult(env, pResult, method, self);
1165
1166    if (UNLIKELY(isSynchronized)) {
1167        dvmUnlockObject(self, lockObj);
1168    }
1169    if (UNLIKELY(method->shouldTrace)) {
1170        logNativeMethodExit(method, self, *pResult);
1171    }
1172}
1173
1174/*
1175 * ===========================================================================
1176 *      JNI implementation
1177 * ===========================================================================
1178 */
1179
1180/*
1181 * Return the version of the native method interface.
1182 */
1183static jint GetVersion(JNIEnv* env) {
1184    /*
1185     * There is absolutely no need to toggle the mode for correct behavior.
1186     * However, it does provide native code with a simple "suspend self
1187     * if necessary" call.
1188     */
1189    ScopedJniThreadState ts(env);
1190    return JNI_VERSION_1_6;
1191}
1192
1193/*
1194 * Create a new class from a bag of bytes.
1195 *
1196 * This is not currently supported within Dalvik.
1197 */
1198static jclass DefineClass(JNIEnv* env, const char *name, jobject loader,
1199    const jbyte* buf, jsize bufLen)
1200{
1201    UNUSED_PARAMETER(name);
1202    UNUSED_PARAMETER(loader);
1203    UNUSED_PARAMETER(buf);
1204    UNUSED_PARAMETER(bufLen);
1205
1206    ScopedJniThreadState ts(env);
1207    ALOGW("JNI DefineClass is not supported");
1208    return NULL;
1209}
1210
1211/*
1212 * Find a class by name.
1213 *
1214 * We have to use the "no init" version of FindClass here, because we might
1215 * be getting the class prior to registering native methods that will be
1216 * used in <clinit>.
1217 *
1218 * We need to get the class loader associated with the current native
1219 * method.  If there is no native method, e.g. we're calling this from native
1220 * code right after creating the VM, the spec says we need to use the class
1221 * loader returned by "ClassLoader.getBaseClassLoader".  There is no such
1222 * method, but it's likely they meant ClassLoader.getSystemClassLoader.
1223 * We can't get that until after the VM has initialized though.
1224 */
1225static jclass FindClass(JNIEnv* env, const char* name) {
1226    ScopedJniThreadState ts(env);
1227
1228    const Method* thisMethod = dvmGetCurrentJNIMethod();
1229    assert(thisMethod != NULL);
1230
1231    Object* loader;
1232    Object* trackedLoader = NULL;
1233    if (ts.self()->classLoaderOverride != NULL) {
1234        /* hack for JNI_OnLoad */
1235        assert(strcmp(thisMethod->name, "nativeLoad") == 0);
1236        loader = ts.self()->classLoaderOverride;
1237    } else if (thisMethod == gDvm.methDalvikSystemNativeStart_main ||
1238               thisMethod == gDvm.methDalvikSystemNativeStart_run) {
1239        /* start point of invocation interface */
1240        if (!gDvm.initializing) {
1241            loader = trackedLoader = dvmGetSystemClassLoader();
1242        } else {
1243            loader = NULL;
1244        }
1245    } else {
1246        loader = thisMethod->clazz->classLoader;
1247    }
1248
1249    char* descriptor = dvmNameToDescriptor(name);
1250    if (descriptor == NULL) {
1251        return NULL;
1252    }
1253    ClassObject* clazz = dvmFindClassNoInit(descriptor, loader);
1254    free(descriptor);
1255
1256    jclass jclazz = (jclass) addLocalReference(ts.self(), (Object*) clazz);
1257    dvmReleaseTrackedAlloc(trackedLoader, ts.self());
1258    return jclazz;
1259}
1260
1261/*
1262 * Return the superclass of a class.
1263 */
1264static jclass GetSuperclass(JNIEnv* env, jclass jclazz) {
1265    ScopedJniThreadState ts(env);
1266    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1267    return (jclass) addLocalReference(ts.self(), (Object*)clazz->super);
1268}
1269
1270/*
1271 * Determine whether an object of clazz1 can be safely cast to clazz2.
1272 *
1273 * Like IsInstanceOf, but with a pair of class objects instead of obj+class.
1274 */
1275static jboolean IsAssignableFrom(JNIEnv* env, jclass jclazz1, jclass jclazz2) {
1276    ScopedJniThreadState ts(env);
1277    ClassObject* clazz1 = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz1);
1278    ClassObject* clazz2 = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz2);
1279    return dvmInstanceof(clazz1, clazz2);
1280}
1281
1282/*
1283 * Given a java.lang.reflect.Method or .Constructor, return a methodID.
1284 */
1285static jmethodID FromReflectedMethod(JNIEnv* env, jobject jmethod) {
1286    ScopedJniThreadState ts(env);
1287    Object* method = dvmDecodeIndirectRef(ts.self(), jmethod);
1288    return (jmethodID) dvmGetMethodFromReflectObj(method);
1289}
1290
1291/*
1292 * Given a java.lang.reflect.Field, return a fieldID.
1293 */
1294static jfieldID FromReflectedField(JNIEnv* env, jobject jfield) {
1295    ScopedJniThreadState ts(env);
1296    Object* field = dvmDecodeIndirectRef(ts.self(), jfield);
1297    return (jfieldID) dvmGetFieldFromReflectObj(field);
1298}
1299
1300/*
1301 * Convert a methodID to a java.lang.reflect.Method or .Constructor.
1302 *
1303 * (The "isStatic" field does not appear in the spec.)
1304 *
1305 * Throws OutOfMemory and returns NULL on failure.
1306 */
1307static jobject ToReflectedMethod(JNIEnv* env, jclass jcls, jmethodID methodID, jboolean isStatic) {
1308    ScopedJniThreadState ts(env);
1309    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jcls);
1310    Object* obj = dvmCreateReflectObjForMethod(clazz, (Method*) methodID);
1311    dvmReleaseTrackedAlloc(obj, NULL);
1312    return addLocalReference(ts.self(), obj);
1313}
1314
1315/*
1316 * Convert a fieldID to a java.lang.reflect.Field.
1317 *
1318 * (The "isStatic" field does not appear in the spec.)
1319 *
1320 * Throws OutOfMemory and returns NULL on failure.
1321 */
1322static jobject ToReflectedField(JNIEnv* env, jclass jcls, jfieldID fieldID, jboolean isStatic) {
1323    ScopedJniThreadState ts(env);
1324    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jcls);
1325    Object* obj = dvmCreateReflectObjForField(clazz, (Field*) fieldID);
1326    dvmReleaseTrackedAlloc(obj, NULL);
1327    return addLocalReference(ts.self(), obj);
1328}
1329
1330/*
1331 * Take this exception and throw it.
1332 */
1333static jint Throw(JNIEnv* env, jthrowable jobj) {
1334    ScopedJniThreadState ts(env);
1335    if (jobj != NULL) {
1336        Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1337        dvmSetException(ts.self(), obj);
1338        return JNI_OK;
1339    }
1340    return JNI_ERR;
1341}
1342
1343/*
1344 * Constructs an exception object from the specified class with the message
1345 * specified by "message", and throws it.
1346 */
1347static jint ThrowNew(JNIEnv* env, jclass jclazz, const char* message) {
1348    ScopedJniThreadState ts(env);
1349    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1350    dvmThrowException(clazz, message);
1351    // TODO: should return failure if this didn't work (e.g. OOM)
1352    return JNI_OK;
1353}
1354
1355/*
1356 * If an exception is being thrown, return the exception object.  Otherwise,
1357 * return NULL.
1358 *
1359 * TODO: if there is no pending exception, we should be able to skip the
1360 * enter/exit checks.  If we find one, we need to enter and then re-fetch
1361 * the exception (in case it got moved by a compacting GC).
1362 */
1363static jthrowable ExceptionOccurred(JNIEnv* env) {
1364    ScopedJniThreadState ts(env);
1365    Object* exception = dvmGetException(ts.self());
1366    jthrowable localException = (jthrowable) addLocalReference(ts.self(), exception);
1367    if (localException == NULL && exception != NULL) {
1368        /*
1369         * We were unable to add a new local reference, and threw a new
1370         * exception.  We can't return "exception", because it's not a
1371         * local reference.  So we have to return NULL, indicating that
1372         * there was no exception, even though it's pretty much raining
1373         * exceptions in here.
1374         */
1375        ALOGW("JNI WARNING: addLocal/exception combo");
1376    }
1377    return localException;
1378}
1379
1380/*
1381 * Print an exception and stack trace to stderr.
1382 */
1383static void ExceptionDescribe(JNIEnv* env) {
1384    ScopedJniThreadState ts(env);
1385    Object* exception = dvmGetException(ts.self());
1386    if (exception != NULL) {
1387        dvmPrintExceptionStackTrace();
1388    } else {
1389        ALOGI("Odd: ExceptionDescribe called, but no exception pending");
1390    }
1391}
1392
1393/*
1394 * Clear the exception currently being thrown.
1395 *
1396 * TODO: we should be able to skip the enter/exit stuff.
1397 */
1398static void ExceptionClear(JNIEnv* env) {
1399    ScopedJniThreadState ts(env);
1400    dvmClearException(ts.self());
1401}
1402
1403/*
1404 * Kill the VM.  This function does not return.
1405 */
1406static void FatalError(JNIEnv* env, const char* msg) {
1407    //dvmChangeStatus(NULL, THREAD_RUNNING);
1408    ALOGE("JNI posting fatal error: %s", msg);
1409    ReportJniError();
1410}
1411
1412/*
1413 * Push a new JNI frame on the stack, with a new set of locals.
1414 *
1415 * The new frame must have the same method pointer.  (If for no other
1416 * reason than FindClass needs it to get the appropriate class loader.)
1417 */
1418static jint PushLocalFrame(JNIEnv* env, jint capacity) {
1419    ScopedJniThreadState ts(env);
1420    if (!ensureLocalCapacity(ts.self(), capacity) ||
1421            !dvmPushLocalFrame(ts.self(), dvmGetCurrentJNIMethod()))
1422    {
1423        /* yes, OutOfMemoryError, not StackOverflowError */
1424        dvmClearException(ts.self());
1425        dvmThrowOutOfMemoryError("out of stack in JNI PushLocalFrame");
1426        return JNI_ERR;
1427    }
1428    return JNI_OK;
1429}
1430
1431/*
1432 * Pop the local frame off.  If "jresult" is not null, add it as a
1433 * local reference on the now-current frame.
1434 */
1435static jobject PopLocalFrame(JNIEnv* env, jobject jresult) {
1436    ScopedJniThreadState ts(env);
1437    Object* result = dvmDecodeIndirectRef(ts.self(), jresult);
1438    if (!dvmPopLocalFrame(ts.self())) {
1439        ALOGW("JNI WARNING: too many PopLocalFrame calls");
1440        dvmClearException(ts.self());
1441        dvmThrowRuntimeException("too many PopLocalFrame calls");
1442    }
1443    return addLocalReference(ts.self(), result);
1444}
1445
1446/*
1447 * Add a reference to the global list.
1448 */
1449static jobject NewGlobalRef(JNIEnv* env, jobject jobj) {
1450    ScopedJniThreadState ts(env);
1451    Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1452    return addGlobalReference(obj);
1453}
1454
1455/*
1456 * Delete a reference from the global list.
1457 */
1458static void DeleteGlobalRef(JNIEnv* env, jobject jglobalRef) {
1459    ScopedJniThreadState ts(env);
1460    deleteGlobalReference(jglobalRef);
1461}
1462
1463
1464/*
1465 * Add a reference to the local list.
1466 */
1467static jobject NewLocalRef(JNIEnv* env, jobject jobj) {
1468    ScopedJniThreadState ts(env);
1469    Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1470    return addLocalReference(ts.self(), obj);
1471}
1472
1473/*
1474 * Delete a reference from the local list.
1475 */
1476static void DeleteLocalRef(JNIEnv* env, jobject jlocalRef) {
1477    ScopedJniThreadState ts(env);
1478    deleteLocalReference(ts.self(), jlocalRef);
1479}
1480
1481/*
1482 * Ensure that the local references table can hold at least this many
1483 * references.
1484 */
1485static jint EnsureLocalCapacity(JNIEnv* env, jint capacity) {
1486    ScopedJniThreadState ts(env);
1487    bool okay = ensureLocalCapacity(ts.self(), capacity);
1488    if (!okay) {
1489        dvmThrowOutOfMemoryError("can't ensure local reference capacity");
1490    }
1491    return okay ? 0 : -1;
1492}
1493
1494
1495/*
1496 * Determine whether two Object references refer to the same underlying object.
1497 */
1498static jboolean IsSameObject(JNIEnv* env, jobject jref1, jobject jref2) {
1499    ScopedJniThreadState ts(env);
1500    Object* obj1 = dvmDecodeIndirectRef(ts.self(), jref1);
1501    Object* obj2 = dvmDecodeIndirectRef(ts.self(), jref2);
1502    return (obj1 == obj2);
1503}
1504
1505/*
1506 * Allocate a new object without invoking any constructors.
1507 */
1508static jobject AllocObject(JNIEnv* env, jclass jclazz) {
1509    ScopedJniThreadState ts(env);
1510
1511    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1512    if (!canAllocClass(clazz) ||
1513        (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)))
1514    {
1515        assert(dvmCheckException(ts.self()));
1516        return NULL;
1517    }
1518
1519    Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1520    return addLocalReference(ts.self(), newObj);
1521}
1522
1523/*
1524 * Allocate a new object and invoke the supplied constructor.
1525 */
1526static jobject NewObject(JNIEnv* env, jclass jclazz, jmethodID methodID, ...) {
1527    ScopedJniThreadState ts(env);
1528    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1529
1530    if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
1531        assert(dvmCheckException(ts.self()));
1532        return NULL;
1533    }
1534
1535    Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1536    jobject result = addLocalReference(ts.self(), newObj);
1537    if (newObj != NULL) {
1538        JValue unused;
1539        va_list args;
1540        va_start(args, methodID);
1541        dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args);
1542        va_end(args);
1543    }
1544    return result;
1545}
1546
1547static jobject NewObjectV(JNIEnv* env, jclass jclazz, jmethodID methodID, va_list args) {
1548    ScopedJniThreadState ts(env);
1549    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1550
1551    if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
1552        assert(dvmCheckException(ts.self()));
1553        return NULL;
1554    }
1555
1556    Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1557    jobject result = addLocalReference(ts.self(), newObj);
1558    if (newObj != NULL) {
1559        JValue unused;
1560        dvmCallMethodV(ts.self(), (Method*) methodID, newObj, true, &unused, args);
1561    }
1562    return result;
1563}
1564
1565static jobject NewObjectA(JNIEnv* env, jclass jclazz, jmethodID methodID, jvalue* args) {
1566    ScopedJniThreadState ts(env);
1567    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1568
1569    if (!canAllocClass(clazz) || (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz))) {
1570        assert(dvmCheckException(ts.self()));
1571        return NULL;
1572    }
1573
1574    Object* newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
1575    jobject result = addLocalReference(ts.self(), newObj);
1576    if (newObj != NULL) {
1577        JValue unused;
1578        dvmCallMethodA(ts.self(), (Method*) methodID, newObj, true, &unused, args);
1579    }
1580    return result;
1581}
1582
1583/*
1584 * Returns the class of an object.
1585 *
1586 * JNI spec says: obj must not be NULL.
1587 */
1588static jclass GetObjectClass(JNIEnv* env, jobject jobj) {
1589    ScopedJniThreadState ts(env);
1590
1591    assert(jobj != NULL);
1592
1593    Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1594    return (jclass) addLocalReference(ts.self(), (Object*) obj->clazz);
1595}
1596
1597/*
1598 * Determine whether "obj" is an instance of "clazz".
1599 */
1600static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass jclazz) {
1601    ScopedJniThreadState ts(env);
1602
1603    assert(jclazz != NULL);
1604    if (jobj == NULL) {
1605        return true;
1606    }
1607
1608    Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
1609    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1610    return dvmInstanceof(obj->clazz, clazz);
1611}
1612
1613/*
1614 * Get a method ID for an instance method.
1615 *
1616 * While Dalvik bytecode has distinct instructions for virtual, super,
1617 * static, direct, and interface method invocation, JNI only provides
1618 * two functions for acquiring a method ID.  This call handles everything
1619 * but static methods.
1620 *
1621 * JNI defines <init> as an instance method, but Dalvik considers it a
1622 * "direct" method, so we have to special-case it here.
1623 *
1624 * Dalvik also puts all private methods into the "direct" list, so we
1625 * really need to just search both lists.
1626 */
1627static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1628    ScopedJniThreadState ts(env);
1629
1630    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1631    if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1632        assert(dvmCheckException(ts.self()));
1633    } else if (dvmIsInterfaceClass(clazz)) {
1634        Method* meth = dvmFindInterfaceMethodHierByDescriptor(clazz, name, sig);
1635        if (meth == NULL) {
1636            dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
1637                "no method with name='%s' signature='%s' in interface %s",
1638                name, sig, clazz->descriptor);
1639        }
1640        return (jmethodID) meth;
1641    }
1642    Method* meth = dvmFindVirtualMethodHierByDescriptor(clazz, name, sig);
1643    if (meth == NULL) {
1644        /* search private methods and constructors; non-hierarchical */
1645        meth = dvmFindDirectMethodByDescriptor(clazz, name, sig);
1646    }
1647    if (meth != NULL && dvmIsStaticMethod(meth)) {
1648        IF_ALOGD() {
1649            char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
1650            ALOGD("GetMethodID: not returning static method %s.%s %s",
1651                    clazz->descriptor, meth->name, desc);
1652            free(desc);
1653        }
1654        meth = NULL;
1655    }
1656    if (meth == NULL) {
1657        dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
1658                "no method with name='%s' signature='%s' in class %s",
1659                name, sig, clazz->descriptor);
1660    } else {
1661        /*
1662         * The method's class may not be the same as clazz, but if
1663         * it isn't this must be a virtual method and the class must
1664         * be a superclass (and, hence, already initialized).
1665         */
1666        assert(dvmIsClassInitialized(meth->clazz) || dvmIsClassInitializing(meth->clazz));
1667    }
1668    return (jmethodID) meth;
1669}
1670
1671/*
1672 * Get a field ID (instance fields).
1673 */
1674static jfieldID GetFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1675    ScopedJniThreadState ts(env);
1676
1677    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1678
1679    if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1680        assert(dvmCheckException(ts.self()));
1681        return NULL;
1682    }
1683
1684    jfieldID id = (jfieldID) dvmFindInstanceFieldHier(clazz, name, sig);
1685    if (id == NULL) {
1686        dvmThrowExceptionFmt(gDvm.exNoSuchFieldError,
1687                "no field with name='%s' signature='%s' in class %s",
1688                name, sig, clazz->descriptor);
1689    }
1690    return id;
1691}
1692
1693/*
1694 * Get the method ID for a static method in a class.
1695 */
1696static jmethodID GetStaticMethodID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1697    ScopedJniThreadState ts(env);
1698
1699    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1700    if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1701        assert(dvmCheckException(ts.self()));
1702        return NULL;
1703    }
1704
1705    Method* meth = dvmFindDirectMethodHierByDescriptor(clazz, name, sig);
1706
1707    /* make sure it's static, not virtual+private */
1708    if (meth != NULL && !dvmIsStaticMethod(meth)) {
1709        IF_ALOGD() {
1710            char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
1711            ALOGD("GetStaticMethodID: not returning nonstatic method %s.%s %s",
1712                    clazz->descriptor, meth->name, desc);
1713            free(desc);
1714        }
1715        meth = NULL;
1716    }
1717
1718    jmethodID id = (jmethodID) meth;
1719    if (id == NULL) {
1720        dvmThrowExceptionFmt(gDvm.exNoSuchMethodError,
1721                "no static method with name='%s' signature='%s' in class %s",
1722                name, sig, clazz->descriptor);
1723    }
1724    return id;
1725}
1726
1727/*
1728 * Get a field ID (static fields).
1729 */
1730static jfieldID GetStaticFieldID(JNIEnv* env, jclass jclazz, const char* name, const char* sig) {
1731    ScopedJniThreadState ts(env);
1732
1733    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
1734    if (!dvmIsClassInitialized(clazz) && !dvmInitClass(clazz)) {
1735        assert(dvmCheckException(ts.self()));
1736        return NULL;
1737    }
1738
1739    jfieldID id = (jfieldID) dvmFindStaticFieldHier(clazz, name, sig);
1740    if (id == NULL) {
1741        dvmThrowExceptionFmt(gDvm.exNoSuchFieldError,
1742                "no static field with name='%s' signature='%s' in class %s",
1743                name, sig, clazz->descriptor);
1744    }
1745    return id;
1746}
1747
1748/*
1749 * Get a static field.
1750 *
1751 * If we get an object reference, add it to the local refs list.
1752 */
1753#define GET_STATIC_TYPE_FIELD(_ctype, _jname, _isref)                       \
1754    static _ctype GetStatic##_jname##Field(JNIEnv* env, jclass jclazz,      \
1755        jfieldID fieldID)                                                   \
1756    {                                                                       \
1757        UNUSED_PARAMETER(jclazz);                                           \
1758        ScopedJniThreadState ts(env);                                       \
1759        StaticField* sfield = (StaticField*) fieldID;                       \
1760        _ctype value;                                                       \
1761        if (dvmIsVolatileField(sfield)) {                                   \
1762            if (_isref) {   /* only when _ctype==jobject */                 \
1763                Object* obj = dvmGetStaticFieldObjectVolatile(sfield);      \
1764                value = (_ctype)(u4)addLocalReference(ts.self(), obj);            \
1765            } else {                                                        \
1766                value = (_ctype) dvmGetStaticField##_jname##Volatile(sfield);\
1767            }                                                               \
1768        } else {                                                            \
1769            if (_isref) {                                                   \
1770                Object* obj = dvmGetStaticFieldObject(sfield);              \
1771                value = (_ctype)(u4)addLocalReference(ts.self(), obj);            \
1772            } else {                                                        \
1773                value = (_ctype) dvmGetStaticField##_jname(sfield);         \
1774            }                                                               \
1775        }                                                                   \
1776        return value;                                                       \
1777    }
1778GET_STATIC_TYPE_FIELD(jobject, Object, true);
1779GET_STATIC_TYPE_FIELD(jboolean, Boolean, false);
1780GET_STATIC_TYPE_FIELD(jbyte, Byte, false);
1781GET_STATIC_TYPE_FIELD(jchar, Char, false);
1782GET_STATIC_TYPE_FIELD(jshort, Short, false);
1783GET_STATIC_TYPE_FIELD(jint, Int, false);
1784GET_STATIC_TYPE_FIELD(jlong, Long, false);
1785GET_STATIC_TYPE_FIELD(jfloat, Float, false);
1786GET_STATIC_TYPE_FIELD(jdouble, Double, false);
1787
1788/*
1789 * Set a static field.
1790 */
1791#define SET_STATIC_TYPE_FIELD(_ctype, _ctype2, _jname, _isref)              \
1792    static void SetStatic##_jname##Field(JNIEnv* env, jclass jclazz,        \
1793        jfieldID fieldID, _ctype value)                                     \
1794    {                                                                       \
1795        UNUSED_PARAMETER(jclazz);                                           \
1796        ScopedJniThreadState ts(env);                                       \
1797        StaticField* sfield = (StaticField*) fieldID;                       \
1798        if (dvmIsVolatileField(sfield)) {                                   \
1799            if (_isref) {   /* only when _ctype==jobject */                 \
1800                Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1801                dvmSetStaticFieldObjectVolatile(sfield, valObj);            \
1802            } else {                                                        \
1803                dvmSetStaticField##_jname##Volatile(sfield, (_ctype2)value);\
1804            }                                                               \
1805        } else {                                                            \
1806            if (_isref) {                                                   \
1807                Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1808                dvmSetStaticFieldObject(sfield, valObj);                    \
1809            } else {                                                        \
1810                dvmSetStaticField##_jname(sfield, (_ctype2)value);          \
1811            }                                                               \
1812        }                                                                   \
1813    }
1814SET_STATIC_TYPE_FIELD(jobject, Object*, Object, true);
1815SET_STATIC_TYPE_FIELD(jboolean, bool, Boolean, false);
1816SET_STATIC_TYPE_FIELD(jbyte, s1, Byte, false);
1817SET_STATIC_TYPE_FIELD(jchar, u2, Char, false);
1818SET_STATIC_TYPE_FIELD(jshort, s2, Short, false);
1819SET_STATIC_TYPE_FIELD(jint, s4, Int, false);
1820SET_STATIC_TYPE_FIELD(jlong, s8, Long, false);
1821SET_STATIC_TYPE_FIELD(jfloat, float, Float, false);
1822SET_STATIC_TYPE_FIELD(jdouble, double, Double, false);
1823
1824/*
1825 * Get an instance field.
1826 *
1827 * If we get an object reference, add it to the local refs list.
1828 */
1829#define GET_TYPE_FIELD(_ctype, _jname, _isref)                              \
1830    static _ctype Get##_jname##Field(JNIEnv* env, jobject jobj,             \
1831        jfieldID fieldID)                                                   \
1832    {                                                                       \
1833        ScopedJniThreadState ts(env);                                       \
1834        Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);                      \
1835        InstField* field = (InstField*) fieldID;                            \
1836        _ctype value;                                                       \
1837        if (dvmIsVolatileField(field)) {                            \
1838            if (_isref) {   /* only when _ctype==jobject */                 \
1839                Object* valObj =                                            \
1840                    dvmGetFieldObjectVolatile(obj, field->byteOffset);      \
1841                value = (_ctype)(u4)addLocalReference(ts.self(), valObj);         \
1842            } else {                                                        \
1843                value = (_ctype)                                            \
1844                    dvmGetField##_jname##Volatile(obj, field->byteOffset);  \
1845            }                                                               \
1846        } else {                                                            \
1847            if (_isref) {                                                   \
1848                Object* valObj = dvmGetFieldObject(obj, field->byteOffset); \
1849                value = (_ctype)(u4)addLocalReference(ts.self(), valObj);         \
1850            } else {                                                        \
1851                value = (_ctype) dvmGetField##_jname(obj, field->byteOffset);\
1852            }                                                               \
1853        }                                                                   \
1854        return value;                                                       \
1855    }
1856GET_TYPE_FIELD(jobject, Object, true);
1857GET_TYPE_FIELD(jboolean, Boolean, false);
1858GET_TYPE_FIELD(jbyte, Byte, false);
1859GET_TYPE_FIELD(jchar, Char, false);
1860GET_TYPE_FIELD(jshort, Short, false);
1861GET_TYPE_FIELD(jint, Int, false);
1862GET_TYPE_FIELD(jlong, Long, false);
1863GET_TYPE_FIELD(jfloat, Float, false);
1864GET_TYPE_FIELD(jdouble, Double, false);
1865
1866/*
1867 * Set an instance field.
1868 */
1869#define SET_TYPE_FIELD(_ctype, _ctype2, _jname, _isref)                     \
1870    static void Set##_jname##Field(JNIEnv* env, jobject jobj,               \
1871        jfieldID fieldID, _ctype value)                                     \
1872    {                                                                       \
1873        ScopedJniThreadState ts(env);                                       \
1874        Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
1875        InstField* field = (InstField*) fieldID;                            \
1876        if (dvmIsVolatileField(field)) {                                    \
1877            if (_isref) {   /* only when _ctype==jobject */                 \
1878                Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1879                dvmSetFieldObjectVolatile(obj, field->byteOffset, valObj);  \
1880            } else {                                                        \
1881                dvmSetField##_jname##Volatile(obj,                          \
1882                    field->byteOffset, (_ctype2)value);                     \
1883            }                                                               \
1884        } else {                                                            \
1885            if (_isref) {                                                   \
1886                Object* valObj = dvmDecodeIndirectRef(ts.self(), (jobject)(u4)value); \
1887                dvmSetFieldObject(obj, field->byteOffset, valObj);          \
1888            } else {                                                        \
1889                dvmSetField##_jname(obj,                                    \
1890                    field->byteOffset, (_ctype2)value);                     \
1891            }                                                               \
1892        }                                                                   \
1893    }
1894SET_TYPE_FIELD(jobject, Object*, Object, true);
1895SET_TYPE_FIELD(jboolean, bool, Boolean, false);
1896SET_TYPE_FIELD(jbyte, s1, Byte, false);
1897SET_TYPE_FIELD(jchar, u2, Char, false);
1898SET_TYPE_FIELD(jshort, s2, Short, false);
1899SET_TYPE_FIELD(jint, s4, Int, false);
1900SET_TYPE_FIELD(jlong, s8, Long, false);
1901SET_TYPE_FIELD(jfloat, float, Float, false);
1902SET_TYPE_FIELD(jdouble, double, Double, false);
1903
1904/*
1905 * Make a virtual method call.
1906 *
1907 * Three versions (..., va_list, jvalue[]) for each return type.  If we're
1908 * returning an Object, we have to add it to the local references table.
1909 */
1910#define CALL_VIRTUAL(_ctype, _jname, _retfail, _retok, _isref)              \
1911    static _ctype Call##_jname##Method(JNIEnv* env, jobject jobj,           \
1912        jmethodID methodID, ...)                                            \
1913    {                                                                       \
1914        ScopedJniThreadState ts(env);                                       \
1915        Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);                      \
1916        const Method* meth;                                                 \
1917        va_list args;                                                       \
1918        JValue result;                                                      \
1919        meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID);      \
1920        if (meth == NULL) {                                                 \
1921            return _retfail;                                                \
1922        }                                                                   \
1923        va_start(args, methodID);                                           \
1924        dvmCallMethodV(ts.self(), meth, obj, true, &result, args);          \
1925        va_end(args);                                                       \
1926        if (_isref && !dvmCheckException(ts.self()))                        \
1927            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
1928        return _retok;                                                      \
1929    }                                                                       \
1930    static _ctype Call##_jname##MethodV(JNIEnv* env, jobject jobj,          \
1931        jmethodID methodID, va_list args)                                   \
1932    {                                                                       \
1933        ScopedJniThreadState ts(env);                                       \
1934        Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);                      \
1935        const Method* meth;                                                 \
1936        JValue result;                                                      \
1937        meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID);      \
1938        if (meth == NULL) {                                                 \
1939            return _retfail;                                                \
1940        }                                                                   \
1941        dvmCallMethodV(ts.self(), meth, obj, true, &result, args);          \
1942        if (_isref && !dvmCheckException(ts.self()))                        \
1943            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
1944        return _retok;                                                      \
1945    }                                                                       \
1946    static _ctype Call##_jname##MethodA(JNIEnv* env, jobject jobj,          \
1947        jmethodID methodID, jvalue* args)                                   \
1948    {                                                                       \
1949        ScopedJniThreadState ts(env);                                       \
1950        Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);                      \
1951        const Method* meth;                                                 \
1952        JValue result;                                                      \
1953        meth = dvmGetVirtualizedMethod(obj->clazz, (Method*)methodID);      \
1954        if (meth == NULL) {                                                 \
1955            return _retfail;                                                \
1956        }                                                                   \
1957        dvmCallMethodA(ts.self(), meth, obj, true, &result, args);          \
1958        if (_isref && !dvmCheckException(ts.self()))                        \
1959            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
1960        return _retok;                                                      \
1961    }
1962CALL_VIRTUAL(jobject, Object, NULL, (jobject) result.l, true);
1963CALL_VIRTUAL(jboolean, Boolean, 0, result.z, false);
1964CALL_VIRTUAL(jbyte, Byte, 0, result.b, false);
1965CALL_VIRTUAL(jchar, Char, 0, result.c, false);
1966CALL_VIRTUAL(jshort, Short, 0, result.s, false);
1967CALL_VIRTUAL(jint, Int, 0, result.i, false);
1968CALL_VIRTUAL(jlong, Long, 0, result.j, false);
1969CALL_VIRTUAL(jfloat, Float, 0.0f, result.f, false);
1970CALL_VIRTUAL(jdouble, Double, 0.0, result.d, false);
1971CALL_VIRTUAL(void, Void, , , false);
1972
1973/*
1974 * Make a "non-virtual" method call.  We're still calling a virtual method,
1975 * but this time we're not doing an indirection through the object's vtable.
1976 * The "clazz" parameter defines which implementation of a method we want.
1977 *
1978 * Three versions (..., va_list, jvalue[]) for each return type.
1979 */
1980#define CALL_NONVIRTUAL(_ctype, _jname, _retfail, _retok, _isref)           \
1981    static _ctype CallNonvirtual##_jname##Method(JNIEnv* env, jobject jobj, \
1982        jclass jclazz, jmethodID methodID, ...)                             \
1983    {                                                                       \
1984        ScopedJniThreadState ts(env);                                       \
1985        Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);                      \
1986        ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz); \
1987        const Method* meth;                                                 \
1988        va_list args;                                                       \
1989        JValue result;                                                      \
1990        meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID);           \
1991        if (meth == NULL) {                                                 \
1992            return _retfail;                                                \
1993        }                                                                   \
1994        va_start(args, methodID);                                           \
1995        dvmCallMethodV(ts.self(), meth, obj, true, &result, args);          \
1996        if (_isref && !dvmCheckException(ts.self()))                        \
1997            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
1998        va_end(args);                                                       \
1999        return _retok;                                                      \
2000    }                                                                       \
2001    static _ctype CallNonvirtual##_jname##MethodV(JNIEnv* env, jobject jobj,\
2002        jclass jclazz, jmethodID methodID, va_list args)                    \
2003    {                                                                       \
2004        ScopedJniThreadState ts(env);                                       \
2005        Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);                      \
2006        ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz); \
2007        const Method* meth;                                                 \
2008        JValue result;                                                      \
2009        meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID);           \
2010        if (meth == NULL) {                                                 \
2011            return _retfail;                                                \
2012        }                                                                   \
2013        dvmCallMethodV(ts.self(), meth, obj, true, &result, args);          \
2014        if (_isref && !dvmCheckException(ts.self()))                        \
2015            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
2016        return _retok;                                                      \
2017    }                                                                       \
2018    static _ctype CallNonvirtual##_jname##MethodA(JNIEnv* env, jobject jobj,\
2019        jclass jclazz, jmethodID methodID, jvalue* args)                    \
2020    {                                                                       \
2021        ScopedJniThreadState ts(env);                                       \
2022        Object* obj = dvmDecodeIndirectRef(ts.self(), jobj); \
2023        ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz); \
2024        const Method* meth;                                                 \
2025        JValue result;                                                      \
2026        meth = dvmGetVirtualizedMethod(clazz, (Method*)methodID);           \
2027        if (meth == NULL) {                                                 \
2028            return _retfail;                                                \
2029        }                                                                   \
2030        dvmCallMethodA(ts.self(), meth, obj, true, &result, args);          \
2031        if (_isref && !dvmCheckException(ts.self()))                        \
2032            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
2033        return _retok;                                                      \
2034    }
2035CALL_NONVIRTUAL(jobject, Object, NULL, (jobject) result.l, true);
2036CALL_NONVIRTUAL(jboolean, Boolean, 0, result.z, false);
2037CALL_NONVIRTUAL(jbyte, Byte, 0, result.b, false);
2038CALL_NONVIRTUAL(jchar, Char, 0, result.c, false);
2039CALL_NONVIRTUAL(jshort, Short, 0, result.s, false);
2040CALL_NONVIRTUAL(jint, Int, 0, result.i, false);
2041CALL_NONVIRTUAL(jlong, Long, 0, result.j, false);
2042CALL_NONVIRTUAL(jfloat, Float, 0.0f, result.f, false);
2043CALL_NONVIRTUAL(jdouble, Double, 0.0, result.d, false);
2044CALL_NONVIRTUAL(void, Void, , , false);
2045
2046
2047/*
2048 * Call a static method.
2049 */
2050#define CALL_STATIC(_ctype, _jname, _retfail, _retok, _isref)               \
2051    static _ctype CallStatic##_jname##Method(JNIEnv* env, jclass jclazz,    \
2052        jmethodID methodID, ...)                                            \
2053    {                                                                       \
2054        UNUSED_PARAMETER(jclazz);                                           \
2055        ScopedJniThreadState ts(env);                                       \
2056        JValue result;                                                      \
2057        va_list args;                                                       \
2058        va_start(args, methodID);                                           \
2059        dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
2060        va_end(args);                                                       \
2061        if (_isref && !dvmCheckException(ts.self()))                        \
2062            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
2063        return _retok;                                                      \
2064    }                                                                       \
2065    static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass jclazz,   \
2066        jmethodID methodID, va_list args)                                   \
2067    {                                                                       \
2068        UNUSED_PARAMETER(jclazz);                                           \
2069        ScopedJniThreadState ts(env);                                       \
2070        JValue result;                                                      \
2071        dvmCallMethodV(ts.self(), (Method*)methodID, NULL, true, &result, args);\
2072        if (_isref && !dvmCheckException(ts.self()))                        \
2073            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
2074        return _retok;                                                      \
2075    }                                                                       \
2076    static _ctype CallStatic##_jname##MethodA(JNIEnv* env, jclass jclazz,   \
2077        jmethodID methodID, jvalue* args)                                   \
2078    {                                                                       \
2079        UNUSED_PARAMETER(jclazz);                                           \
2080        ScopedJniThreadState ts(env);                                       \
2081        JValue result;                                                      \
2082        dvmCallMethodA(ts.self(), (Method*)methodID, NULL, true, &result, args);\
2083        if (_isref && !dvmCheckException(ts.self()))                        \
2084            result.l = (Object*)addLocalReference(ts.self(), result.l);           \
2085        return _retok;                                                      \
2086    }
2087CALL_STATIC(jobject, Object, NULL, (jobject) result.l, true);
2088CALL_STATIC(jboolean, Boolean, 0, result.z, false);
2089CALL_STATIC(jbyte, Byte, 0, result.b, false);
2090CALL_STATIC(jchar, Char, 0, result.c, false);
2091CALL_STATIC(jshort, Short, 0, result.s, false);
2092CALL_STATIC(jint, Int, 0, result.i, false);
2093CALL_STATIC(jlong, Long, 0, result.j, false);
2094CALL_STATIC(jfloat, Float, 0.0f, result.f, false);
2095CALL_STATIC(jdouble, Double, 0.0, result.d, false);
2096CALL_STATIC(void, Void, , , false);
2097
2098/*
2099 * Create a new String from Unicode data.
2100 *
2101 * If "len" is zero, we will return an empty string even if "unicodeChars"
2102 * is NULL.  (The JNI spec is vague here.)
2103 */
2104static jstring NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) {
2105    ScopedJniThreadState ts(env);
2106    StringObject* jstr = dvmCreateStringFromUnicode(unicodeChars, len);
2107    if (jstr == NULL) {
2108        return NULL;
2109    }
2110    dvmReleaseTrackedAlloc((Object*) jstr, NULL);
2111    return (jstring) addLocalReference(ts.self(), (Object*) jstr);
2112}
2113
2114/*
2115 * Return the length of a String in Unicode character units.
2116 */
2117static jsize GetStringLength(JNIEnv* env, jstring jstr) {
2118    ScopedJniThreadState ts(env);
2119    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2120    return strObj->length();
2121}
2122
2123
2124/*
2125 * Get a string's character data.
2126 *
2127 * The result is guaranteed to be valid until ReleaseStringChars is
2128 * called, which means we have to pin it or return a copy.
2129 */
2130static const jchar* GetStringChars(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2131    ScopedJniThreadState ts(env);
2132
2133    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2134    ArrayObject* strChars = strObj->array();
2135
2136    pinPrimitiveArray(strChars);
2137
2138    const u2* data = strObj->chars();
2139    if (isCopy != NULL) {
2140        *isCopy = JNI_FALSE;
2141    }
2142    return (jchar*) data;
2143}
2144
2145/*
2146 * Release our grip on some characters from a string.
2147 */
2148static void ReleaseStringChars(JNIEnv* env, jstring jstr, const jchar* chars) {
2149    ScopedJniThreadState ts(env);
2150    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2151    ArrayObject* strChars = strObj->array();
2152    unpinPrimitiveArray(strChars);
2153}
2154
2155/*
2156 * Create a new java.lang.String object from chars in modified UTF-8 form.
2157 *
2158 * The spec doesn't say how to handle a NULL string.  Popular desktop VMs
2159 * accept it and return a NULL pointer in response.
2160 */
2161static jstring NewStringUTF(JNIEnv* env, const char* bytes) {
2162    ScopedJniThreadState ts(env);
2163    if (bytes == NULL) {
2164        return NULL;
2165    }
2166    /* note newStr could come back NULL on OOM */
2167    StringObject* newStr = dvmCreateStringFromCstr(bytes);
2168    jstring result = (jstring) addLocalReference(ts.self(), (Object*) newStr);
2169    dvmReleaseTrackedAlloc((Object*)newStr, NULL);
2170    return result;
2171}
2172
2173/*
2174 * Return the length in bytes of the modified UTF-8 form of the string.
2175 */
2176static jsize GetStringUTFLength(JNIEnv* env, jstring jstr) {
2177    ScopedJniThreadState ts(env);
2178    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2179    if (strObj == NULL) {
2180        return 0; // Should we throw something or assert?
2181    }
2182    return strObj->utfLength();
2183}
2184
2185/*
2186 * Convert "string" to modified UTF-8 and return a pointer.  The returned
2187 * value must be released with ReleaseStringUTFChars.
2188 *
2189 * According to the JNI reference, "Returns a pointer to a UTF-8 string,
2190 * or NULL if the operation fails. Returns NULL if and only if an invocation
2191 * of this function has thrown an exception."
2192 *
2193 * The behavior here currently follows that of other open-source VMs, which
2194 * quietly return NULL if "string" is NULL.  We should consider throwing an
2195 * NPE.  (The CheckJNI code blows up if you try to pass in a NULL string,
2196 * which should catch this sort of thing during development.)  Certain other
2197 * VMs will crash with a segmentation fault.
2198 */
2199static const char* GetStringUTFChars(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2200    ScopedJniThreadState ts(env);
2201    if (jstr == NULL) {
2202        /* this shouldn't happen; throw NPE? */
2203        return NULL;
2204    }
2205    if (isCopy != NULL) {
2206        *isCopy = JNI_TRUE;
2207    }
2208    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2209    char* newStr = dvmCreateCstrFromString(strObj);
2210    if (newStr == NULL) {
2211        /* assume memory failure */
2212        dvmThrowOutOfMemoryError("native heap string alloc failed");
2213    }
2214    return newStr;
2215}
2216
2217/*
2218 * Release a string created by GetStringUTFChars().
2219 */
2220static void ReleaseStringUTFChars(JNIEnv* env, jstring jstr, const char* utf) {
2221    ScopedJniThreadState ts(env);
2222    free((char*) utf);
2223}
2224
2225/*
2226 * Return the capacity of the array.
2227 */
2228static jsize GetArrayLength(JNIEnv* env, jarray jarr) {
2229    ScopedJniThreadState ts(env);
2230    ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2231    return arrObj->length;
2232}
2233
2234/*
2235 * Construct a new array that holds objects from class "elementClass".
2236 */
2237static jobjectArray NewObjectArray(JNIEnv* env, jsize length,
2238    jclass jelementClass, jobject jinitialElement)
2239{
2240    ScopedJniThreadState ts(env);
2241
2242    if (jelementClass == NULL) {
2243        dvmThrowNullPointerException("JNI NewObjectArray elementClass == NULL");
2244        return NULL;
2245    }
2246
2247    ClassObject* elemClassObj = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jelementClass);
2248    ClassObject* arrayClass = dvmFindArrayClassForElement(elemClassObj);
2249    ArrayObject* newObj = dvmAllocArrayByClass(arrayClass, length, ALLOC_DEFAULT);
2250    if (newObj == NULL) {
2251        assert(dvmCheckException(ts.self()));
2252        return NULL;
2253    }
2254    jobjectArray newArray = (jobjectArray) addLocalReference(ts.self(), (Object*) newObj);
2255    dvmReleaseTrackedAlloc((Object*) newObj, NULL);
2256
2257    /*
2258     * Initialize the array.
2259     */
2260    if (jinitialElement != NULL) {
2261        Object* initialElement = dvmDecodeIndirectRef(ts.self(), jinitialElement);
2262        Object** arrayData = (Object**) (void*) newObj->contents;
2263        for (jsize i = 0; i < length; ++i) {
2264            arrayData[i] = initialElement;
2265        }
2266    }
2267
2268    return newArray;
2269}
2270
2271static bool checkArrayElementBounds(ArrayObject* arrayObj, jsize index) {
2272    assert(arrayObj != NULL);
2273    if (index < 0 || index >= (int) arrayObj->length) {
2274        dvmThrowArrayIndexOutOfBoundsException(arrayObj->length, index);
2275        return false;
2276    }
2277    return true;
2278}
2279
2280/*
2281 * Get one element of an Object array.
2282 *
2283 * Add the object to the local references table in case the array goes away.
2284 */
2285static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index) {
2286    ScopedJniThreadState ts(env);
2287
2288    ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2289    if (!checkArrayElementBounds(arrayObj, index)) {
2290        return NULL;
2291    }
2292
2293    Object* value = ((Object**) (void*) arrayObj->contents)[index];
2294    return addLocalReference(ts.self(), value);
2295}
2296
2297/*
2298 * Set one element of an Object array.
2299 */
2300static void SetObjectArrayElement(JNIEnv* env, jobjectArray jarr, jsize index, jobject jobj) {
2301    ScopedJniThreadState ts(env);
2302
2303    ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2304    if (!checkArrayElementBounds(arrayObj, index)) {
2305        return;
2306    }
2307
2308    Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
2309
2310    if (obj != NULL && !dvmCanPutArrayElement(obj->clazz, arrayObj->clazz)) {
2311      ALOGV("Can't put a '%s'(%p) into array type='%s'(%p)",
2312            obj->clazz->descriptor, obj,
2313            arrayObj->clazz->descriptor, arrayObj);
2314      dvmThrowArrayStoreExceptionIncompatibleElement(obj->clazz, arrayObj->clazz);
2315      return;
2316    }
2317
2318    //ALOGV("JNI: set element %d in array %p to %p", index, array, value);
2319
2320    dvmSetObjectArrayElement(arrayObj, index, obj);
2321}
2322
2323/*
2324 * Create a new array of primitive elements.
2325 */
2326#define NEW_PRIMITIVE_ARRAY(_artype, _jname, _typechar) \
2327    static _artype New##_jname##Array(JNIEnv* env, jsize length) { \
2328        ScopedJniThreadState ts(env); \
2329        ArrayObject* arrayObj = dvmAllocPrimitiveArray(_typechar, length, ALLOC_DEFAULT); \
2330        if (arrayObj == NULL) { \
2331            return NULL; \
2332        } \
2333        _artype result = (_artype) addLocalReference(ts.self(), (Object*) arrayObj); \
2334        dvmReleaseTrackedAlloc((Object*) arrayObj, NULL); \
2335        return result; \
2336    }
2337NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean, 'Z');
2338NEW_PRIMITIVE_ARRAY(jbyteArray, Byte, 'B');
2339NEW_PRIMITIVE_ARRAY(jcharArray, Char, 'C');
2340NEW_PRIMITIVE_ARRAY(jshortArray, Short, 'S');
2341NEW_PRIMITIVE_ARRAY(jintArray, Int, 'I');
2342NEW_PRIMITIVE_ARRAY(jlongArray, Long, 'J');
2343NEW_PRIMITIVE_ARRAY(jfloatArray, Float, 'F');
2344NEW_PRIMITIVE_ARRAY(jdoubleArray, Double, 'D');
2345
2346/*
2347 * Get a pointer to a C array of primitive elements from an array object
2348 * of the matching type.
2349 *
2350 * In a compacting GC, we either need to return a copy of the elements or
2351 * "pin" the memory.  Otherwise we run the risk of native code using the
2352 * buffer as the destination of e.g. a blocking read() call that wakes up
2353 * during a GC.
2354 */
2355#define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
2356    static _ctype* Get##_jname##ArrayElements(JNIEnv* env, \
2357        _ctype##Array jarr, jboolean* isCopy) \
2358    { \
2359        ScopedJniThreadState ts(env); \
2360        ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2361        pinPrimitiveArray(arrayObj); \
2362        _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2363        if (isCopy != NULL) { \
2364            *isCopy = JNI_FALSE; \
2365        } \
2366        return data; \
2367    }
2368
2369/*
2370 * Release the storage locked down by the "get" function.
2371 *
2372 * The spec says, "'mode' has no effect if 'elems' is not a copy of the
2373 * elements in 'array'."  They apparently did not anticipate the need to
2374 * un-pin memory.
2375 */
2376#define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname)                    \
2377    static void Release##_jname##ArrayElements(JNIEnv* env,                 \
2378        _ctype##Array jarr, _ctype* elems, jint mode)                       \
2379    {                                                                       \
2380        UNUSED_PARAMETER(elems);                                            \
2381        if (mode != JNI_COMMIT) {                                           \
2382            ScopedJniThreadState ts(env);                                   \
2383            ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2384            unpinPrimitiveArray(arrayObj);                                  \
2385        }                                                                   \
2386    }
2387
2388static void throwArrayRegionOutOfBounds(ArrayObject* arrayObj, jsize start,
2389    jsize len, const char* arrayIdentifier)
2390{
2391    dvmThrowExceptionFmt(gDvm.exArrayIndexOutOfBoundsException,
2392        "%s offset=%d length=%d %s.length=%d",
2393        arrayObj->clazz->descriptor, start, len, arrayIdentifier,
2394        arrayObj->length);
2395}
2396
2397/*
2398 * Copy a section of a primitive array to a buffer.
2399 */
2400#define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
2401    static void Get##_jname##ArrayRegion(JNIEnv* env, \
2402        _ctype##Array jarr, jsize start, jsize len, _ctype* buf) \
2403    { \
2404        ScopedJniThreadState ts(env); \
2405        ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2406        _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2407        if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
2408            throwArrayRegionOutOfBounds(arrayObj, start, len, "src"); \
2409        } else { \
2410            memcpy(buf, data + start, len * sizeof(_ctype)); \
2411        } \
2412    }
2413
2414/*
2415 * Copy a section of a primitive array from a buffer.
2416 */
2417#define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
2418    static void Set##_jname##ArrayRegion(JNIEnv* env, \
2419        _ctype##Array jarr, jsize start, jsize len, const _ctype* buf) \
2420    { \
2421        ScopedJniThreadState ts(env); \
2422        ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2423        _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2424        if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
2425            throwArrayRegionOutOfBounds(arrayObj, start, len, "dst"); \
2426        } else { \
2427            memcpy(data + start, buf, len * sizeof(_ctype)); \
2428        } \
2429    }
2430
2431/*
2432 * 4-in-1:
2433 *  Get<Type>ArrayElements
2434 *  Release<Type>ArrayElements
2435 *  Get<Type>ArrayRegion
2436 *  Set<Type>ArrayRegion
2437 */
2438#define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname)                           \
2439    GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname);                           \
2440    RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname);                       \
2441    GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);                             \
2442    SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
2443
2444PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean);
2445PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte);
2446PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char);
2447PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short);
2448PRIMITIVE_ARRAY_FUNCTIONS(jint, Int);
2449PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long);
2450PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float);
2451PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double);
2452
2453/*
2454 * Register one or more native functions in one class.
2455 *
2456 * This can be called multiple times on the same method, allowing the
2457 * caller to redefine the method implementation at will.
2458 */
2459static jint RegisterNatives(JNIEnv* env, jclass jclazz,
2460    const JNINativeMethod* methods, jint nMethods)
2461{
2462    ScopedJniThreadState ts(env);
2463
2464    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
2465
2466    if (gDvm.verboseJni) {
2467        ALOGI("[Registering JNI native methods for class %s]",
2468            clazz->descriptor);
2469    }
2470
2471    for (int i = 0; i < nMethods; i++) {
2472        if (!dvmRegisterJNIMethod(clazz, methods[i].name,
2473                methods[i].signature, methods[i].fnPtr))
2474        {
2475            return JNI_ERR;
2476        }
2477    }
2478    return JNI_OK;
2479}
2480
2481/*
2482 * Un-register all native methods associated with the class.
2483 *
2484 * The JNI docs refer to this as a way to reload/relink native libraries,
2485 * and say it "should not be used in normal native code".  In particular,
2486 * there is no need to do this during shutdown, and you do not need to do
2487 * this before redefining a method implementation with RegisterNatives.
2488 *
2489 * It's chiefly useful for a native "plugin"-style library that wasn't
2490 * loaded with System.loadLibrary() (since there's no way to unload those).
2491 * For example, the library could upgrade itself by:
2492 *
2493 *  1. call UnregisterNatives to unbind the old methods
2494 *  2. ensure that no code is still executing inside it (somehow)
2495 *  3. dlclose() the library
2496 *  4. dlopen() the new library
2497 *  5. use RegisterNatives to bind the methods from the new library
2498 *
2499 * The above can work correctly without the UnregisterNatives call, but
2500 * creates a window of opportunity in which somebody might try to call a
2501 * method that is pointing at unmapped memory, crashing the VM.  In theory
2502 * the same guards that prevent dlclose() from unmapping executing code could
2503 * prevent that anyway, but with this we can be more thorough and also deal
2504 * with methods that only exist in the old or new form of the library (maybe
2505 * the lib wants to try the call and catch the UnsatisfiedLinkError).
2506 */
2507static jint UnregisterNatives(JNIEnv* env, jclass jclazz) {
2508    ScopedJniThreadState ts(env);
2509
2510    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
2511    if (gDvm.verboseJni) {
2512        ALOGI("[Unregistering JNI native methods for class %s]",
2513            clazz->descriptor);
2514    }
2515    dvmUnregisterJNINativeMethods(clazz);
2516    return JNI_OK;
2517}
2518
2519/*
2520 * Lock the monitor.
2521 *
2522 * We have to track all monitor enters and exits, so that we can undo any
2523 * outstanding synchronization before the thread exits.
2524 */
2525static jint MonitorEnter(JNIEnv* env, jobject jobj) {
2526    ScopedJniThreadState ts(env);
2527    Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
2528    dvmLockObject(ts.self(), obj);
2529    trackMonitorEnter(ts.self(), obj);
2530    return JNI_OK;
2531}
2532
2533/*
2534 * Unlock the monitor.
2535 *
2536 * Throws an IllegalMonitorStateException if the current thread
2537 * doesn't own the monitor.  (dvmUnlockObject() takes care of the throw.)
2538 *
2539 * According to the 1.6 spec, it's legal to call here with an exception
2540 * pending.  If this fails, we'll stomp the original exception.
2541 */
2542static jint MonitorExit(JNIEnv* env, jobject jobj) {
2543    ScopedJniThreadState ts(env);
2544    Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
2545    bool success = dvmUnlockObject(ts.self(), obj);
2546    if (success) {
2547        trackMonitorExit(ts.self(), obj);
2548    }
2549    return success ? JNI_OK : JNI_ERR;
2550}
2551
2552/*
2553 * Return the JavaVM interface associated with the current thread.
2554 */
2555static jint GetJavaVM(JNIEnv* env, JavaVM** vm) {
2556    ScopedJniThreadState ts(env);
2557    *vm = gDvmJni.jniVm;
2558    return (*vm == NULL) ? JNI_ERR : JNI_OK;
2559}
2560
2561/*
2562 * Copies "len" Unicode characters, from offset "start".
2563 */
2564static void GetStringRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, jchar* buf) {
2565    ScopedJniThreadState ts(env);
2566    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2567    int strLen = strObj->length();
2568    if (((start|len) < 0) || (start + len > strLen)) {
2569        dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
2570        return;
2571    }
2572    memcpy(buf, strObj->chars() + start, len * sizeof(u2));
2573}
2574
2575/*
2576 * Translates "len" Unicode characters, from offset "start", into
2577 * modified UTF-8 encoding.
2578 */
2579static void GetStringUTFRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, char* buf) {
2580    ScopedJniThreadState ts(env);
2581    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2582    int strLen = strObj->length();
2583    if (((start|len) < 0) || (start + len > strLen)) {
2584        dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
2585        return;
2586    }
2587    dvmGetStringUtfRegion(strObj, start, len, buf);
2588}
2589
2590/*
2591 * Get a raw pointer to array data.
2592 *
2593 * The caller is expected to call "release" before doing any JNI calls
2594 * or blocking I/O operations.
2595 *
2596 * We need to pin the memory or block GC.
2597 */
2598static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray jarr, jboolean* isCopy) {
2599    ScopedJniThreadState ts(env);
2600    ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2601    pinPrimitiveArray(arrayObj);
2602    void* data = arrayObj->contents;
2603    if (UNLIKELY(isCopy != NULL)) {
2604        *isCopy = JNI_FALSE;
2605    }
2606    return data;
2607}
2608
2609/*
2610 * Release an array obtained with GetPrimitiveArrayCritical.
2611 */
2612static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray jarr, void* carray, jint mode) {
2613    if (mode != JNI_COMMIT) {
2614        ScopedJniThreadState ts(env);
2615        ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2616        unpinPrimitiveArray(arrayObj);
2617    }
2618}
2619
2620/*
2621 * Like GetStringChars, but with restricted use.
2622 */
2623static const jchar* GetStringCritical(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2624    ScopedJniThreadState ts(env);
2625
2626    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2627    ArrayObject* strChars = strObj->array();
2628
2629    pinPrimitiveArray(strChars);
2630
2631    const u2* data = strObj->chars();
2632    if (isCopy != NULL) {
2633        *isCopy = JNI_FALSE;
2634    }
2635    return (jchar*) data;
2636}
2637
2638/*
2639 * Like ReleaseStringChars, but with restricted use.
2640 */
2641static void ReleaseStringCritical(JNIEnv* env, jstring jstr, const jchar* carray) {
2642    ScopedJniThreadState ts(env);
2643    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2644    ArrayObject* strChars = strObj->array();
2645    unpinPrimitiveArray(strChars);
2646}
2647
2648/*
2649 * Create a new weak global reference.
2650 */
2651static jweak NewWeakGlobalRef(JNIEnv* env, jobject jobj) {
2652    ScopedJniThreadState ts(env);
2653    Object *obj = dvmDecodeIndirectRef(ts.self(), jobj);
2654    return (jweak) addWeakGlobalReference(obj);
2655}
2656
2657/*
2658 * Delete the specified weak global reference.
2659 */
2660static void DeleteWeakGlobalRef(JNIEnv* env, jweak wref) {
2661    ScopedJniThreadState ts(env);
2662    deleteWeakGlobalReference(wref);
2663}
2664
2665/*
2666 * Quick check for pending exceptions.
2667 *
2668 * TODO: we should be able to skip the enter/exit macros here.
2669 */
2670static jboolean ExceptionCheck(JNIEnv* env) {
2671    ScopedJniThreadState ts(env);
2672    return dvmCheckException(ts.self());
2673}
2674
2675/*
2676 * Returns the type of the object referred to by "obj".  It can be local,
2677 * global, or weak global.
2678 *
2679 * In the current implementation, references can be global and local at
2680 * the same time, so while the return value is accurate it may not tell
2681 * the whole story.
2682 */
2683static jobjectRefType GetObjectRefType(JNIEnv* env, jobject jobj) {
2684    ScopedJniThreadState ts(env);
2685    return dvmGetJNIRefType(ts.self(), jobj);
2686}
2687
2688/*
2689 * Allocate and return a new java.nio.ByteBuffer for this block of memory.
2690 */
2691static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
2692    ScopedJniThreadState ts(env);
2693
2694    if (capacity < 0) {
2695        ALOGE("JNI ERROR (app bug): negative buffer capacity: %lld", capacity);
2696        ReportJniError();
2697    }
2698    if (address == NULL && capacity != 0) {
2699        ALOGE("JNI ERROR (app bug): non-zero capacity for NULL pointer: %lld", capacity);
2700        ReportJniError();
2701    }
2702
2703    /* create an instance of java.nio.DirectByteBuffer */
2704    ClassObject* bufferClazz = gDvm.classJavaNioDirectByteBuffer;
2705    if (!dvmIsClassInitialized(bufferClazz) && !dvmInitClass(bufferClazz)) {
2706        return NULL;
2707    }
2708    Object* newObj = dvmAllocObject(bufferClazz, ALLOC_DONT_TRACK);
2709    if (newObj == NULL) {
2710        return NULL;
2711    }
2712    /* call the constructor */
2713    jobject result = addLocalReference(ts.self(), newObj);
2714    JValue unused;
2715    dvmCallMethod(ts.self(), gDvm.methJavaNioDirectByteBuffer_init,
2716            newObj, &unused, (jlong) address, (jint) capacity);
2717    if (dvmGetException(ts.self()) != NULL) {
2718        deleteLocalReference(ts.self(), result);
2719        return NULL;
2720    }
2721    return result;
2722}
2723
2724/*
2725 * Get the starting address of the buffer for the specified java.nio.Buffer.
2726 *
2727 * If this is not a "direct" buffer, we return NULL.
2728 */
2729static void* GetDirectBufferAddress(JNIEnv* env, jobject jbuf) {
2730    ScopedJniThreadState ts(env);
2731
2732    // All Buffer objects have an effectiveDirectAddress field.
2733    Object* bufObj = dvmDecodeIndirectRef(ts.self(), jbuf);
2734    return (void*) dvmGetFieldLong(bufObj, gDvm.offJavaNioBuffer_effectiveDirectAddress);
2735}
2736
2737/*
2738 * Get the capacity of the buffer for the specified java.nio.Buffer.
2739 *
2740 * Returns -1 if the object is not a direct buffer.  (We actually skip
2741 * this check, since it's expensive to determine, and just return the
2742 * capacity regardless.)
2743 */
2744static jlong GetDirectBufferCapacity(JNIEnv* env, jobject jbuf) {
2745    ScopedJniThreadState ts(env);
2746
2747    /*
2748     * The capacity is always in the Buffer.capacity field.
2749     *
2750     * (The "check" version should verify that this is actually a Buffer,
2751     * but we're not required to do so here.)
2752     */
2753    Object* buf = dvmDecodeIndirectRef(ts.self(), jbuf);
2754    return dvmGetFieldInt(buf, gDvm.offJavaNioBuffer_capacity);
2755}
2756
2757
2758/*
2759 * ===========================================================================
2760 *      JNI invocation functions
2761 * ===========================================================================
2762 */
2763
2764/*
2765 * Handle AttachCurrentThread{AsDaemon}.
2766 *
2767 * We need to make sure the VM is actually running.  For example, if we start
2768 * up, issue an Attach, and the VM exits almost immediately, by the time the
2769 * attaching happens the VM could already be shutting down.
2770 *
2771 * It's hard to avoid a race condition here because we don't want to hold
2772 * a lock across the entire operation.  What we can do is temporarily
2773 * increment the thread count to prevent a VM exit.
2774 *
2775 * This could potentially still have problems if a daemon thread calls here
2776 * while the VM is shutting down.  dvmThreadSelf() will work, since it just
2777 * uses pthread TLS, but dereferencing "vm" could fail.  Such is life when
2778 * you shut down a VM while threads are still running inside it.
2779 *
2780 * Remember that some code may call this as a way to find the per-thread
2781 * JNIEnv pointer.  Don't do excess work for that case.
2782 */
2783static jint attachThread(JavaVM* vm, JNIEnv** p_env, void* thr_args, bool isDaemon) {
2784    JavaVMAttachArgs* args = (JavaVMAttachArgs*) thr_args;
2785
2786    /*
2787     * Return immediately if we're already one with the VM.
2788     */
2789    Thread* self = dvmThreadSelf();
2790    if (self != NULL) {
2791        *p_env = self->jniEnv;
2792        return JNI_OK;
2793    }
2794
2795    /*
2796     * No threads allowed in zygote mode.
2797     */
2798    if (gDvm.zygote) {
2799        return JNI_ERR;
2800    }
2801
2802    /* increment the count to keep the VM from bailing while we run */
2803    dvmLockThreadList(NULL);
2804    if (gDvm.nonDaemonThreadCount == 0) {
2805        // dead or dying
2806        ALOGV("Refusing to attach thread '%s' -- VM is shutting down",
2807            (thr_args == NULL) ? "(unknown)" : args->name);
2808        dvmUnlockThreadList();
2809        return JNI_ERR;
2810    }
2811    gDvm.nonDaemonThreadCount++;
2812    dvmUnlockThreadList();
2813
2814    /* tweak the JavaVMAttachArgs as needed */
2815    JavaVMAttachArgs argsCopy;
2816    if (args == NULL) {
2817        /* allow the v1.1 calling convention */
2818        argsCopy.version = JNI_VERSION_1_2;
2819        argsCopy.name = NULL;
2820        argsCopy.group = (jobject) dvmGetMainThreadGroup();
2821    } else {
2822        if (dvmIsBadJniVersion(args->version)) {
2823            ALOGE("Bad JNI version passed to %s: %d",
2824                  (isDaemon ? "AttachCurrentThreadAsDaemon" : "AttachCurrentThread"),
2825                  args->version);
2826            return JNI_EVERSION;
2827        }
2828
2829        argsCopy.version = args->version;
2830        argsCopy.name = args->name;
2831        if (args->group != NULL) {
2832            argsCopy.group = (jobject) dvmDecodeIndirectRef(NULL, args->group);
2833        } else {
2834            argsCopy.group = (jobject) dvmGetMainThreadGroup();
2835        }
2836    }
2837
2838    bool result = dvmAttachCurrentThread(&argsCopy, isDaemon);
2839
2840    /* restore the count */
2841    dvmLockThreadList(NULL);
2842    gDvm.nonDaemonThreadCount--;
2843    dvmUnlockThreadList();
2844
2845    /*
2846     * Change the status to indicate that we're out in native code.  This
2847     * call is not guarded with state-change macros, so we have to do it
2848     * by hand.
2849     */
2850    if (result) {
2851        self = dvmThreadSelf();
2852        assert(self != NULL);
2853        dvmChangeStatus(self, THREAD_NATIVE);
2854        *p_env = self->jniEnv;
2855        return JNI_OK;
2856    } else {
2857        return JNI_ERR;
2858    }
2859}
2860
2861/*
2862 * Attach the current thread to the VM.  If the thread is already attached,
2863 * this is a no-op.
2864 */
2865static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
2866    return attachThread(vm, p_env, thr_args, false);
2867}
2868
2869/*
2870 * Like AttachCurrentThread, but set the "daemon" flag.
2871 */
2872static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args)
2873{
2874    return attachThread(vm, p_env, thr_args, true);
2875}
2876
2877/*
2878 * Dissociate the current thread from the VM.
2879 */
2880static jint DetachCurrentThread(JavaVM* vm) {
2881    Thread* self = dvmThreadSelf();
2882    if (self == NULL) {
2883        /* not attached, can't do anything */
2884        return JNI_ERR;
2885    }
2886
2887    /* switch to "running" to check for suspension */
2888    dvmChangeStatus(self, THREAD_RUNNING);
2889
2890    /* detach the thread */
2891    dvmDetachCurrentThread();
2892
2893    /* (no need to change status back -- we have no status) */
2894    return JNI_OK;
2895}
2896
2897/*
2898 * If current thread is attached to VM, return the associated JNIEnv.
2899 * Otherwise, stuff NULL in and return JNI_EDETACHED.
2900 *
2901 * JVMTI overloads this by specifying a magic value for "version", so we
2902 * do want to check that here.
2903 */
2904static jint GetEnv(JavaVM* vm, void** env, jint version) {
2905    Thread* self = dvmThreadSelf();
2906
2907    // GetEnv also accepts JNI_VERSION_1_1, but always returns a JNIEnv*
2908    // corresponding to the most current supported JNI version.
2909    if (dvmIsBadJniVersion(version) && version != JNI_VERSION_1_1) {
2910        ALOGE("Bad JNI version passed to GetEnv: %d", version);
2911        return JNI_EVERSION;
2912    }
2913
2914    if (self == NULL) {
2915        *env = NULL;
2916    } else {
2917        /* TODO: status change is probably unnecessary */
2918        dvmChangeStatus(self, THREAD_RUNNING);
2919        *env = (void*) dvmGetThreadJNIEnv(self);
2920        dvmChangeStatus(self, THREAD_NATIVE);
2921    }
2922    return (*env != NULL) ? JNI_OK : JNI_EDETACHED;
2923}
2924
2925/*
2926 * Destroy the VM.  This may be called from any thread.
2927 *
2928 * If the current thread is attached, wait until the current thread is
2929 * the only non-daemon user-level thread.  If the current thread is not
2930 * attached, we attach it and do the processing as usual.  (If the attach
2931 * fails, it's probably because all the non-daemon threads have already
2932 * exited and the VM doesn't want to let us back in.)
2933 *
2934 * TODO: we don't really deal with the situation where more than one thread
2935 * has called here.  One thread wins, the other stays trapped waiting on
2936 * the condition variable forever.  Not sure this situation is interesting
2937 * in real life.
2938 */
2939static jint DestroyJavaVM(JavaVM* vm) {
2940    JavaVMExt* ext = (JavaVMExt*) vm;
2941    if (ext == NULL) {
2942        return JNI_ERR;
2943    }
2944
2945    if (gDvm.verboseShutdown) {
2946        ALOGD("DestroyJavaVM waiting for non-daemon threads to exit");
2947    }
2948
2949    /*
2950     * Sleep on a condition variable until it's okay to exit.
2951     */
2952    Thread* self = dvmThreadSelf();
2953    if (self == NULL) {
2954        JNIEnv* tmpEnv;
2955        if (AttachCurrentThread(vm, &tmpEnv, NULL) != JNI_OK) {
2956            ALOGV("Unable to reattach main for Destroy; assuming VM is shutting down (count=%d)",
2957                gDvm.nonDaemonThreadCount);
2958            goto shutdown;
2959        } else {
2960            ALOGV("Attached to wait for shutdown in Destroy");
2961        }
2962    }
2963    dvmChangeStatus(self, THREAD_VMWAIT);
2964
2965    dvmLockThreadList(self);
2966    gDvm.nonDaemonThreadCount--;    // remove current thread from count
2967
2968    while (gDvm.nonDaemonThreadCount > 0) {
2969        pthread_cond_wait(&gDvm.vmExitCond, &gDvm.threadListLock);
2970    }
2971
2972    dvmUnlockThreadList();
2973    self = NULL;
2974
2975shutdown:
2976    // TODO: call System.exit() to run any registered shutdown hooks
2977    // (this may not return -- figure out how this should work)
2978
2979    if (gDvm.verboseShutdown) {
2980        ALOGD("DestroyJavaVM shutting VM down");
2981    }
2982    dvmShutdown();
2983
2984    // TODO - free resources associated with JNI-attached daemon threads
2985    free(ext->envList);
2986    free(ext);
2987
2988    return JNI_OK;
2989}
2990
2991
2992/*
2993 * ===========================================================================
2994 *      Function tables
2995 * ===========================================================================
2996 */
2997
2998static const struct JNINativeInterface gNativeInterface = {
2999    NULL,
3000    NULL,
3001    NULL,
3002    NULL,
3003
3004    GetVersion,
3005
3006    DefineClass,
3007    FindClass,
3008
3009    FromReflectedMethod,
3010    FromReflectedField,
3011    ToReflectedMethod,
3012
3013    GetSuperclass,
3014    IsAssignableFrom,
3015
3016    ToReflectedField,
3017
3018    Throw,
3019    ThrowNew,
3020    ExceptionOccurred,
3021    ExceptionDescribe,
3022    ExceptionClear,
3023    FatalError,
3024
3025    PushLocalFrame,
3026    PopLocalFrame,
3027
3028    NewGlobalRef,
3029    DeleteGlobalRef,
3030    DeleteLocalRef,
3031    IsSameObject,
3032    NewLocalRef,
3033    EnsureLocalCapacity,
3034
3035    AllocObject,
3036    NewObject,
3037    NewObjectV,
3038    NewObjectA,
3039
3040    GetObjectClass,
3041    IsInstanceOf,
3042
3043    GetMethodID,
3044
3045    CallObjectMethod,
3046    CallObjectMethodV,
3047    CallObjectMethodA,
3048    CallBooleanMethod,
3049    CallBooleanMethodV,
3050    CallBooleanMethodA,
3051    CallByteMethod,
3052    CallByteMethodV,
3053    CallByteMethodA,
3054    CallCharMethod,
3055    CallCharMethodV,
3056    CallCharMethodA,
3057    CallShortMethod,
3058    CallShortMethodV,
3059    CallShortMethodA,
3060    CallIntMethod,
3061    CallIntMethodV,
3062    CallIntMethodA,
3063    CallLongMethod,
3064    CallLongMethodV,
3065    CallLongMethodA,
3066    CallFloatMethod,
3067    CallFloatMethodV,
3068    CallFloatMethodA,
3069    CallDoubleMethod,
3070    CallDoubleMethodV,
3071    CallDoubleMethodA,
3072    CallVoidMethod,
3073    CallVoidMethodV,
3074    CallVoidMethodA,
3075
3076    CallNonvirtualObjectMethod,
3077    CallNonvirtualObjectMethodV,
3078    CallNonvirtualObjectMethodA,
3079    CallNonvirtualBooleanMethod,
3080    CallNonvirtualBooleanMethodV,
3081    CallNonvirtualBooleanMethodA,
3082    CallNonvirtualByteMethod,
3083    CallNonvirtualByteMethodV,
3084    CallNonvirtualByteMethodA,
3085    CallNonvirtualCharMethod,
3086    CallNonvirtualCharMethodV,
3087    CallNonvirtualCharMethodA,
3088    CallNonvirtualShortMethod,
3089    CallNonvirtualShortMethodV,
3090    CallNonvirtualShortMethodA,
3091    CallNonvirtualIntMethod,
3092    CallNonvirtualIntMethodV,
3093    CallNonvirtualIntMethodA,
3094    CallNonvirtualLongMethod,
3095    CallNonvirtualLongMethodV,
3096    CallNonvirtualLongMethodA,
3097    CallNonvirtualFloatMethod,
3098    CallNonvirtualFloatMethodV,
3099    CallNonvirtualFloatMethodA,
3100    CallNonvirtualDoubleMethod,
3101    CallNonvirtualDoubleMethodV,
3102    CallNonvirtualDoubleMethodA,
3103    CallNonvirtualVoidMethod,
3104    CallNonvirtualVoidMethodV,
3105    CallNonvirtualVoidMethodA,
3106
3107    GetFieldID,
3108
3109    GetObjectField,
3110    GetBooleanField,
3111    GetByteField,
3112    GetCharField,
3113    GetShortField,
3114    GetIntField,
3115    GetLongField,
3116    GetFloatField,
3117    GetDoubleField,
3118    SetObjectField,
3119    SetBooleanField,
3120    SetByteField,
3121    SetCharField,
3122    SetShortField,
3123    SetIntField,
3124    SetLongField,
3125    SetFloatField,
3126    SetDoubleField,
3127
3128    GetStaticMethodID,
3129
3130    CallStaticObjectMethod,
3131    CallStaticObjectMethodV,
3132    CallStaticObjectMethodA,
3133    CallStaticBooleanMethod,
3134    CallStaticBooleanMethodV,
3135    CallStaticBooleanMethodA,
3136    CallStaticByteMethod,
3137    CallStaticByteMethodV,
3138    CallStaticByteMethodA,
3139    CallStaticCharMethod,
3140    CallStaticCharMethodV,
3141    CallStaticCharMethodA,
3142    CallStaticShortMethod,
3143    CallStaticShortMethodV,
3144    CallStaticShortMethodA,
3145    CallStaticIntMethod,
3146    CallStaticIntMethodV,
3147    CallStaticIntMethodA,
3148    CallStaticLongMethod,
3149    CallStaticLongMethodV,
3150    CallStaticLongMethodA,
3151    CallStaticFloatMethod,
3152    CallStaticFloatMethodV,
3153    CallStaticFloatMethodA,
3154    CallStaticDoubleMethod,
3155    CallStaticDoubleMethodV,
3156    CallStaticDoubleMethodA,
3157    CallStaticVoidMethod,
3158    CallStaticVoidMethodV,
3159    CallStaticVoidMethodA,
3160
3161    GetStaticFieldID,
3162
3163    GetStaticObjectField,
3164    GetStaticBooleanField,
3165    GetStaticByteField,
3166    GetStaticCharField,
3167    GetStaticShortField,
3168    GetStaticIntField,
3169    GetStaticLongField,
3170    GetStaticFloatField,
3171    GetStaticDoubleField,
3172
3173    SetStaticObjectField,
3174    SetStaticBooleanField,
3175    SetStaticByteField,
3176    SetStaticCharField,
3177    SetStaticShortField,
3178    SetStaticIntField,
3179    SetStaticLongField,
3180    SetStaticFloatField,
3181    SetStaticDoubleField,
3182
3183    NewString,
3184
3185    GetStringLength,
3186    GetStringChars,
3187    ReleaseStringChars,
3188
3189    NewStringUTF,
3190    GetStringUTFLength,
3191    GetStringUTFChars,
3192    ReleaseStringUTFChars,
3193
3194    GetArrayLength,
3195    NewObjectArray,
3196    GetObjectArrayElement,
3197    SetObjectArrayElement,
3198
3199    NewBooleanArray,
3200    NewByteArray,
3201    NewCharArray,
3202    NewShortArray,
3203    NewIntArray,
3204    NewLongArray,
3205    NewFloatArray,
3206    NewDoubleArray,
3207
3208    GetBooleanArrayElements,
3209    GetByteArrayElements,
3210    GetCharArrayElements,
3211    GetShortArrayElements,
3212    GetIntArrayElements,
3213    GetLongArrayElements,
3214    GetFloatArrayElements,
3215    GetDoubleArrayElements,
3216
3217    ReleaseBooleanArrayElements,
3218    ReleaseByteArrayElements,
3219    ReleaseCharArrayElements,
3220    ReleaseShortArrayElements,
3221    ReleaseIntArrayElements,
3222    ReleaseLongArrayElements,
3223    ReleaseFloatArrayElements,
3224    ReleaseDoubleArrayElements,
3225
3226    GetBooleanArrayRegion,
3227    GetByteArrayRegion,
3228    GetCharArrayRegion,
3229    GetShortArrayRegion,
3230    GetIntArrayRegion,
3231    GetLongArrayRegion,
3232    GetFloatArrayRegion,
3233    GetDoubleArrayRegion,
3234    SetBooleanArrayRegion,
3235    SetByteArrayRegion,
3236    SetCharArrayRegion,
3237    SetShortArrayRegion,
3238    SetIntArrayRegion,
3239    SetLongArrayRegion,
3240    SetFloatArrayRegion,
3241    SetDoubleArrayRegion,
3242
3243    RegisterNatives,
3244    UnregisterNatives,
3245
3246    MonitorEnter,
3247    MonitorExit,
3248
3249    GetJavaVM,
3250
3251    GetStringRegion,
3252    GetStringUTFRegion,
3253
3254    GetPrimitiveArrayCritical,
3255    ReleasePrimitiveArrayCritical,
3256
3257    GetStringCritical,
3258    ReleaseStringCritical,
3259
3260    NewWeakGlobalRef,
3261    DeleteWeakGlobalRef,
3262
3263    ExceptionCheck,
3264
3265    NewDirectByteBuffer,
3266    GetDirectBufferAddress,
3267    GetDirectBufferCapacity,
3268
3269    GetObjectRefType
3270};
3271
3272static const struct JNIInvokeInterface gInvokeInterface = {
3273    NULL,
3274    NULL,
3275    NULL,
3276
3277    DestroyJavaVM,
3278    AttachCurrentThread,
3279    DetachCurrentThread,
3280
3281    GetEnv,
3282
3283    AttachCurrentThreadAsDaemon,
3284};
3285
3286/*
3287 * ===========================================================================
3288 *      VM/Env creation
3289 * ===========================================================================
3290 */
3291
3292/*
3293 * Create a new JNIEnv struct and add it to the VM's list.
3294 *
3295 * "self" will be NULL for the main thread, since the VM hasn't started
3296 * yet; the value will be filled in later.
3297 */
3298JNIEnv* dvmCreateJNIEnv(Thread* self) {
3299    JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
3300
3301    //if (self != NULL)
3302    //    ALOGI("Ent CreateJNIEnv: threadid=%d %p", self->threadId, self);
3303
3304    assert(vm != NULL);
3305
3306    JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
3307    newEnv->funcTable = &gNativeInterface;
3308    if (self != NULL) {
3309        dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
3310        assert(newEnv->envThreadId != 0);
3311    } else {
3312        /* make it obvious if we fail to initialize these later */
3313        newEnv->envThreadId = 0x77777775;
3314        newEnv->self = (Thread*) 0x77777779;
3315    }
3316    if (gDvmJni.useCheckJni) {
3317        dvmUseCheckedJniEnv(newEnv);
3318    }
3319
3320    ScopedPthreadMutexLock lock(&vm->envListLock);
3321
3322    /* insert at head of list */
3323    newEnv->next = vm->envList;
3324    assert(newEnv->prev == NULL);
3325    if (vm->envList == NULL) {
3326        // rare, but possible
3327        vm->envList = newEnv;
3328    } else {
3329        vm->envList->prev = newEnv;
3330    }
3331    vm->envList = newEnv;
3332
3333    //if (self != NULL)
3334    //    ALOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self);
3335    return (JNIEnv*) newEnv;
3336}
3337
3338/*
3339 * Remove a JNIEnv struct from the list and free it.
3340 */
3341void dvmDestroyJNIEnv(JNIEnv* env) {
3342    if (env == NULL) {
3343        return;
3344    }
3345
3346    //ALOGI("Ent DestroyJNIEnv: threadid=%d %p", self->threadId, self);
3347
3348    JNIEnvExt* extEnv = (JNIEnvExt*) env;
3349    JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
3350
3351    ScopedPthreadMutexLock lock(&vm->envListLock);
3352
3353    if (extEnv == vm->envList) {
3354        assert(extEnv->prev == NULL);
3355        vm->envList = extEnv->next;
3356    } else {
3357        assert(extEnv->prev != NULL);
3358        extEnv->prev->next = extEnv->next;
3359    }
3360    if (extEnv->next != NULL) {
3361        extEnv->next->prev = extEnv->prev;
3362    }
3363
3364    free(env);
3365    //ALOGI("Xit DestroyJNIEnv: threadid=%d %p", self->threadId, self);
3366}
3367
3368/*
3369 * Enable "checked JNI" after the VM has partially started.  This must
3370 * only be called in "zygote" mode, when we have one thread running.
3371 *
3372 * This doesn't attempt to rewrite the JNI call bridge associated with
3373 * native methods, so we won't get those checks for any methods that have
3374 * already been resolved.
3375 */
3376void dvmLateEnableCheckedJni() {
3377    JNIEnvExt* extEnv = dvmGetJNIEnvForThread();
3378    if (extEnv == NULL) {
3379        ALOGE("dvmLateEnableCheckedJni: thread has no JNIEnv");
3380        return;
3381    }
3382    JavaVMExt* extVm = (JavaVMExt*) gDvmJni.jniVm;
3383    assert(extVm != NULL);
3384
3385    if (!gDvmJni.useCheckJni) {
3386        ALOGD("Late-enabling CheckJNI");
3387        dvmUseCheckedJniVm(extVm);
3388        dvmUseCheckedJniEnv(extEnv);
3389    } else {
3390        ALOGD("Not late-enabling CheckJNI (already on)");
3391    }
3392}
3393
3394/*
3395 * Not supported.
3396 */
3397jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
3398    return JNI_ERR;
3399}
3400
3401/*
3402 * Return a buffer full of created VMs.
3403 *
3404 * We always have zero or one.
3405 */
3406jint JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs) {
3407    if (gDvmJni.jniVm != NULL) {
3408        *nVMs = 1;
3409        if (bufLen > 0) {
3410            *vmBuf++ = gDvmJni.jniVm;
3411        }
3412    } else {
3413        *nVMs = 0;
3414    }
3415    return JNI_OK;
3416}
3417
3418/*
3419 * Create a new VM instance.
3420 *
3421 * The current thread becomes the main VM thread.  We return immediately,
3422 * which effectively means the caller is executing in a native method.
3423 */
3424jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
3425    const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args;
3426    if (dvmIsBadJniVersion(args->version)) {
3427        ALOGE("Bad JNI version passed to CreateJavaVM: %d", args->version);
3428        return JNI_EVERSION;
3429    }
3430
3431    // TODO: don't allow creation of multiple VMs -- one per customer for now
3432
3433    /* zero globals; not strictly necessary the first time a VM is started */
3434    memset(&gDvm, 0, sizeof(gDvm));
3435
3436    /*
3437     * Set up structures for JNIEnv and VM.
3438     */
3439    JavaVMExt* pVM = (JavaVMExt*) calloc(1, sizeof(JavaVMExt));
3440    pVM->funcTable = &gInvokeInterface;
3441    pVM->envList = NULL;
3442    dvmInitMutex(&pVM->envListLock);
3443
3444    UniquePtr<const char*[]> argv(new const char*[args->nOptions]);
3445    memset(argv.get(), 0, sizeof(char*) * (args->nOptions));
3446
3447    /*
3448     * Convert JNI args to argv.
3449     *
3450     * We have to pull out vfprintf/exit/abort, because they use the
3451     * "extraInfo" field to pass function pointer "hooks" in.  We also
3452     * look for the -Xcheck:jni stuff here.
3453     */
3454    int argc = 0;
3455    for (int i = 0; i < args->nOptions; i++) {
3456        const char* optStr = args->options[i].optionString;
3457        if (optStr == NULL) {
3458            dvmFprintf(stderr, "ERROR: CreateJavaVM failed: argument %d was NULL\n", i);
3459            return JNI_ERR;
3460        } else if (strcmp(optStr, "vfprintf") == 0) {
3461            gDvm.vfprintfHook = (int (*)(FILE *, const char*, va_list))args->options[i].extraInfo;
3462        } else if (strcmp(optStr, "exit") == 0) {
3463            gDvm.exitHook = (void (*)(int)) args->options[i].extraInfo;
3464        } else if (strcmp(optStr, "abort") == 0) {
3465            gDvm.abortHook = (void (*)(void))args->options[i].extraInfo;
3466        } else if (strcmp(optStr, "sensitiveThread") == 0) {
3467            gDvm.isSensitiveThreadHook = (bool (*)(void))args->options[i].extraInfo;
3468        } else if (strcmp(optStr, "-Xcheck:jni") == 0) {
3469            gDvmJni.useCheckJni = true;
3470        } else if (strncmp(optStr, "-Xjniopts:", 10) == 0) {
3471            char* jniOpts = strdup(optStr + 10);
3472            size_t jniOptCount = 1;
3473            for (char* p = jniOpts; *p != 0; ++p) {
3474                if (*p == ',') {
3475                    ++jniOptCount;
3476                    *p = 0;
3477                }
3478            }
3479            char* jniOpt = jniOpts;
3480            for (size_t i = 0; i < jniOptCount; ++i) {
3481                if (strcmp(jniOpt, "warnonly") == 0) {
3482                    gDvmJni.warnOnly = true;
3483                } else if (strcmp(jniOpt, "forcecopy") == 0) {
3484                    gDvmJni.forceCopy = true;
3485                } else if (strcmp(jniOpt, "logThirdPartyJni") == 0) {
3486                    gDvmJni.logThirdPartyJni = true;
3487                } else {
3488                    dvmFprintf(stderr, "ERROR: CreateJavaVM failed: unknown -Xjniopts option '%s'\n",
3489                            jniOpt);
3490                    free(pVM);
3491                    free(jniOpts);
3492                    return JNI_ERR;
3493                }
3494                jniOpt += strlen(jniOpt) + 1;
3495            }
3496            free(jniOpts);
3497        } else {
3498            /* regular option */
3499            argv[argc++] = optStr;
3500        }
3501    }
3502
3503    if (gDvmJni.useCheckJni) {
3504        dvmUseCheckedJniVm(pVM);
3505    }
3506
3507    if (gDvmJni.jniVm != NULL) {
3508        dvmFprintf(stderr, "ERROR: Dalvik only supports one VM per process\n");
3509        free(pVM);
3510        return JNI_ERR;
3511    }
3512    gDvmJni.jniVm = (JavaVM*) pVM;
3513
3514    /*
3515     * Create a JNIEnv for the main thread.  We need to have something set up
3516     * here because some of the class initialization we do when starting
3517     * up the VM will call into native code.
3518     */
3519    JNIEnvExt* pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);
3520
3521    /* Initialize VM. */
3522    gDvm.initializing = true;
3523    std::string status =
3524            dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);
3525    gDvm.initializing = false;
3526
3527    if (!status.empty()) {
3528        free(pEnv);
3529        free(pVM);
3530        ALOGW("CreateJavaVM failed: %s", status.c_str());
3531        return JNI_ERR;
3532    }
3533
3534    /*
3535     * Success!  Return stuff to caller.
3536     */
3537    dvmChangeStatus(NULL, THREAD_NATIVE);
3538    *p_env = (JNIEnv*) pEnv;
3539    *p_vm = (JavaVM*) pVM;
3540    ALOGV("CreateJavaVM succeeded");
3541    return JNI_OK;
3542}
3543