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