Jni.cpp revision e8e1ddccd616e8226b7cc1e4e9fdb327429249e8
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                LOGE("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                LOGE("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                LOGE("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                LOGE("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    LOGE("Failed adding to JNI local ref table (has %zd entries)", pRefTable->capacity());
366    dvmDumpThread(dvmThreadSelf(), false);
367    dvmAbort();     // spec says call FatalError; this is equivalent
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        LOGE("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                    LOGE("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        LOGE("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        LOGE("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            LOGE("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    LOGE("ERROR: couldn't find native method");
699    LOGE("Requested: %s.%s:%s", clazz->descriptor, methodName, signature);
700    dumpMethods(clazz->virtualMethods, clazz->virtualMethodCount, methodName);
701    dumpMethods(clazz->directMethods, clazz->directMethodCount, methodName);
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            LOGE("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            LOGE("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            LOGE("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        LOGE("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        LOGE("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    LOGE("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    //ALOGV("JNI: set element %d in array %p to %p", index, array, value);
2305
2306    Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
2307    dvmSetObjectArrayElement(arrayObj, index, obj);
2308}
2309
2310/*
2311 * Create a new array of primitive elements.
2312 */
2313#define NEW_PRIMITIVE_ARRAY(_artype, _jname, _typechar) \
2314    static _artype New##_jname##Array(JNIEnv* env, jsize length) { \
2315        ScopedJniThreadState ts(env); \
2316        ArrayObject* arrayObj = dvmAllocPrimitiveArray(_typechar, length, ALLOC_DEFAULT); \
2317        if (arrayObj == NULL) { \
2318            return NULL; \
2319        } \
2320        _artype result = (_artype) addLocalReference(ts.self(), (Object*) arrayObj); \
2321        dvmReleaseTrackedAlloc((Object*) arrayObj, NULL); \
2322        return result; \
2323    }
2324NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean, 'Z');
2325NEW_PRIMITIVE_ARRAY(jbyteArray, Byte, 'B');
2326NEW_PRIMITIVE_ARRAY(jcharArray, Char, 'C');
2327NEW_PRIMITIVE_ARRAY(jshortArray, Short, 'S');
2328NEW_PRIMITIVE_ARRAY(jintArray, Int, 'I');
2329NEW_PRIMITIVE_ARRAY(jlongArray, Long, 'J');
2330NEW_PRIMITIVE_ARRAY(jfloatArray, Float, 'F');
2331NEW_PRIMITIVE_ARRAY(jdoubleArray, Double, 'D');
2332
2333/*
2334 * Get a pointer to a C array of primitive elements from an array object
2335 * of the matching type.
2336 *
2337 * In a compacting GC, we either need to return a copy of the elements or
2338 * "pin" the memory.  Otherwise we run the risk of native code using the
2339 * buffer as the destination of e.g. a blocking read() call that wakes up
2340 * during a GC.
2341 */
2342#define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
2343    static _ctype* Get##_jname##ArrayElements(JNIEnv* env, \
2344        _ctype##Array jarr, jboolean* isCopy) \
2345    { \
2346        ScopedJniThreadState ts(env); \
2347        ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2348        pinPrimitiveArray(arrayObj); \
2349        _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2350        if (isCopy != NULL) { \
2351            *isCopy = JNI_FALSE; \
2352        } \
2353        return data; \
2354    }
2355
2356/*
2357 * Release the storage locked down by the "get" function.
2358 *
2359 * The spec says, "'mode' has no effect if 'elems' is not a copy of the
2360 * elements in 'array'."  They apparently did not anticipate the need to
2361 * un-pin memory.
2362 */
2363#define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname)                    \
2364    static void Release##_jname##ArrayElements(JNIEnv* env,                 \
2365        _ctype##Array jarr, _ctype* elems, jint mode)                       \
2366    {                                                                       \
2367        UNUSED_PARAMETER(elems);                                            \
2368        if (mode != JNI_COMMIT) {                                           \
2369            ScopedJniThreadState ts(env);                                   \
2370            ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2371            unpinPrimitiveArray(arrayObj);                                  \
2372        }                                                                   \
2373    }
2374
2375static void throwArrayRegionOutOfBounds(ArrayObject* arrayObj, jsize start,
2376    jsize len, const char* arrayIdentifier)
2377{
2378    dvmThrowExceptionFmt(gDvm.exArrayIndexOutOfBoundsException,
2379        "%s offset=%d length=%d %s.length=%d",
2380        arrayObj->clazz->descriptor, start, len, arrayIdentifier,
2381        arrayObj->length);
2382}
2383
2384/*
2385 * Copy a section of a primitive array to a buffer.
2386 */
2387#define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
2388    static void Get##_jname##ArrayRegion(JNIEnv* env, \
2389        _ctype##Array jarr, jsize start, jsize len, _ctype* buf) \
2390    { \
2391        ScopedJniThreadState ts(env); \
2392        ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2393        _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2394        if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
2395            throwArrayRegionOutOfBounds(arrayObj, start, len, "src"); \
2396        } else { \
2397            memcpy(buf, data + start, len * sizeof(_ctype)); \
2398        } \
2399    }
2400
2401/*
2402 * Copy a section of a primitive array from a buffer.
2403 */
2404#define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
2405    static void Set##_jname##ArrayRegion(JNIEnv* env, \
2406        _ctype##Array jarr, jsize start, jsize len, const _ctype* buf) \
2407    { \
2408        ScopedJniThreadState ts(env); \
2409        ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr); \
2410        _ctype* data = (_ctype*) (void*) arrayObj->contents; \
2411        if (start < 0 || len < 0 || start + len > (int) arrayObj->length) { \
2412            throwArrayRegionOutOfBounds(arrayObj, start, len, "dst"); \
2413        } else { \
2414            memcpy(data + start, buf, len * sizeof(_ctype)); \
2415        } \
2416    }
2417
2418/*
2419 * 4-in-1:
2420 *  Get<Type>ArrayElements
2421 *  Release<Type>ArrayElements
2422 *  Get<Type>ArrayRegion
2423 *  Set<Type>ArrayRegion
2424 */
2425#define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname)                           \
2426    GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname);                           \
2427    RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname);                       \
2428    GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);                             \
2429    SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
2430
2431PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean);
2432PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte);
2433PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char);
2434PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short);
2435PRIMITIVE_ARRAY_FUNCTIONS(jint, Int);
2436PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long);
2437PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float);
2438PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double);
2439
2440/*
2441 * Register one or more native functions in one class.
2442 *
2443 * This can be called multiple times on the same method, allowing the
2444 * caller to redefine the method implementation at will.
2445 */
2446static jint RegisterNatives(JNIEnv* env, jclass jclazz,
2447    const JNINativeMethod* methods, jint nMethods)
2448{
2449    ScopedJniThreadState ts(env);
2450
2451    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
2452
2453    if (gDvm.verboseJni) {
2454        ALOGI("[Registering JNI native methods for class %s]",
2455            clazz->descriptor);
2456    }
2457
2458    for (int i = 0; i < nMethods; i++) {
2459        if (!dvmRegisterJNIMethod(clazz, methods[i].name,
2460                methods[i].signature, methods[i].fnPtr))
2461        {
2462            return JNI_ERR;
2463        }
2464    }
2465    return JNI_OK;
2466}
2467
2468/*
2469 * Un-register all native methods associated with the class.
2470 *
2471 * The JNI docs refer to this as a way to reload/relink native libraries,
2472 * and say it "should not be used in normal native code".  In particular,
2473 * there is no need to do this during shutdown, and you do not need to do
2474 * this before redefining a method implementation with RegisterNatives.
2475 *
2476 * It's chiefly useful for a native "plugin"-style library that wasn't
2477 * loaded with System.loadLibrary() (since there's no way to unload those).
2478 * For example, the library could upgrade itself by:
2479 *
2480 *  1. call UnregisterNatives to unbind the old methods
2481 *  2. ensure that no code is still executing inside it (somehow)
2482 *  3. dlclose() the library
2483 *  4. dlopen() the new library
2484 *  5. use RegisterNatives to bind the methods from the new library
2485 *
2486 * The above can work correctly without the UnregisterNatives call, but
2487 * creates a window of opportunity in which somebody might try to call a
2488 * method that is pointing at unmapped memory, crashing the VM.  In theory
2489 * the same guards that prevent dlclose() from unmapping executing code could
2490 * prevent that anyway, but with this we can be more thorough and also deal
2491 * with methods that only exist in the old or new form of the library (maybe
2492 * the lib wants to try the call and catch the UnsatisfiedLinkError).
2493 */
2494static jint UnregisterNatives(JNIEnv* env, jclass jclazz) {
2495    ScopedJniThreadState ts(env);
2496
2497    ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(ts.self(), jclazz);
2498    if (gDvm.verboseJni) {
2499        ALOGI("[Unregistering JNI native methods for class %s]",
2500            clazz->descriptor);
2501    }
2502    dvmUnregisterJNINativeMethods(clazz);
2503    return JNI_OK;
2504}
2505
2506/*
2507 * Lock the monitor.
2508 *
2509 * We have to track all monitor enters and exits, so that we can undo any
2510 * outstanding synchronization before the thread exits.
2511 */
2512static jint MonitorEnter(JNIEnv* env, jobject jobj) {
2513    ScopedJniThreadState ts(env);
2514    Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
2515    dvmLockObject(ts.self(), obj);
2516    trackMonitorEnter(ts.self(), obj);
2517    return JNI_OK;
2518}
2519
2520/*
2521 * Unlock the monitor.
2522 *
2523 * Throws an IllegalMonitorStateException if the current thread
2524 * doesn't own the monitor.  (dvmUnlockObject() takes care of the throw.)
2525 *
2526 * According to the 1.6 spec, it's legal to call here with an exception
2527 * pending.  If this fails, we'll stomp the original exception.
2528 */
2529static jint MonitorExit(JNIEnv* env, jobject jobj) {
2530    ScopedJniThreadState ts(env);
2531    Object* obj = dvmDecodeIndirectRef(ts.self(), jobj);
2532    bool success = dvmUnlockObject(ts.self(), obj);
2533    if (success) {
2534        trackMonitorExit(ts.self(), obj);
2535    }
2536    return success ? JNI_OK : JNI_ERR;
2537}
2538
2539/*
2540 * Return the JavaVM interface associated with the current thread.
2541 */
2542static jint GetJavaVM(JNIEnv* env, JavaVM** vm) {
2543    ScopedJniThreadState ts(env);
2544    *vm = gDvmJni.jniVm;
2545    return (*vm == NULL) ? JNI_ERR : JNI_OK;
2546}
2547
2548/*
2549 * Copies "len" Unicode characters, from offset "start".
2550 */
2551static void GetStringRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, jchar* buf) {
2552    ScopedJniThreadState ts(env);
2553    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2554    int strLen = strObj->length();
2555    if (((start|len) < 0) || (start + len > strLen)) {
2556        dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
2557        return;
2558    }
2559    memcpy(buf, strObj->chars() + start, len * sizeof(u2));
2560}
2561
2562/*
2563 * Translates "len" Unicode characters, from offset "start", into
2564 * modified UTF-8 encoding.
2565 */
2566static void GetStringUTFRegion(JNIEnv* env, jstring jstr, jsize start, jsize len, char* buf) {
2567    ScopedJniThreadState ts(env);
2568    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2569    int strLen = strObj->length();
2570    if (((start|len) < 0) || (start + len > strLen)) {
2571        dvmThrowStringIndexOutOfBoundsExceptionWithRegion(strLen, start, len);
2572        return;
2573    }
2574    dvmGetStringUtfRegion(strObj, start, len, buf);
2575}
2576
2577/*
2578 * Get a raw pointer to array data.
2579 *
2580 * The caller is expected to call "release" before doing any JNI calls
2581 * or blocking I/O operations.
2582 *
2583 * We need to pin the memory or block GC.
2584 */
2585static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray jarr, jboolean* isCopy) {
2586    ScopedJniThreadState ts(env);
2587    ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2588    pinPrimitiveArray(arrayObj);
2589    void* data = arrayObj->contents;
2590    if (UNLIKELY(isCopy != NULL)) {
2591        *isCopy = JNI_FALSE;
2592    }
2593    return data;
2594}
2595
2596/*
2597 * Release an array obtained with GetPrimitiveArrayCritical.
2598 */
2599static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray jarr, void* carray, jint mode) {
2600    if (mode != JNI_COMMIT) {
2601        ScopedJniThreadState ts(env);
2602        ArrayObject* arrayObj = (ArrayObject*) dvmDecodeIndirectRef(ts.self(), jarr);
2603        unpinPrimitiveArray(arrayObj);
2604    }
2605}
2606
2607/*
2608 * Like GetStringChars, but with restricted use.
2609 */
2610static const jchar* GetStringCritical(JNIEnv* env, jstring jstr, jboolean* isCopy) {
2611    ScopedJniThreadState ts(env);
2612
2613    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2614    ArrayObject* strChars = strObj->array();
2615
2616    pinPrimitiveArray(strChars);
2617
2618    const u2* data = strObj->chars();
2619    if (isCopy != NULL) {
2620        *isCopy = JNI_FALSE;
2621    }
2622    return (jchar*) data;
2623}
2624
2625/*
2626 * Like ReleaseStringChars, but with restricted use.
2627 */
2628static void ReleaseStringCritical(JNIEnv* env, jstring jstr, const jchar* carray) {
2629    ScopedJniThreadState ts(env);
2630    StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(ts.self(), jstr);
2631    ArrayObject* strChars = strObj->array();
2632    unpinPrimitiveArray(strChars);
2633}
2634
2635/*
2636 * Create a new weak global reference.
2637 */
2638static jweak NewWeakGlobalRef(JNIEnv* env, jobject jobj) {
2639    ScopedJniThreadState ts(env);
2640    Object *obj = dvmDecodeIndirectRef(ts.self(), jobj);
2641    return (jweak) addWeakGlobalReference(obj);
2642}
2643
2644/*
2645 * Delete the specified weak global reference.
2646 */
2647static void DeleteWeakGlobalRef(JNIEnv* env, jweak wref) {
2648    ScopedJniThreadState ts(env);
2649    deleteWeakGlobalReference(wref);
2650}
2651
2652/*
2653 * Quick check for pending exceptions.
2654 *
2655 * TODO: we should be able to skip the enter/exit macros here.
2656 */
2657static jboolean ExceptionCheck(JNIEnv* env) {
2658    ScopedJniThreadState ts(env);
2659    return dvmCheckException(ts.self());
2660}
2661
2662/*
2663 * Returns the type of the object referred to by "obj".  It can be local,
2664 * global, or weak global.
2665 *
2666 * In the current implementation, references can be global and local at
2667 * the same time, so while the return value is accurate it may not tell
2668 * the whole story.
2669 */
2670static jobjectRefType GetObjectRefType(JNIEnv* env, jobject jobj) {
2671    ScopedJniThreadState ts(env);
2672    return dvmGetJNIRefType(ts.self(), jobj);
2673}
2674
2675/*
2676 * Allocate and return a new java.nio.ByteBuffer for this block of memory.
2677 *
2678 * "address" may not be NULL, and "capacity" must be > 0.  (These are only
2679 * verified when CheckJNI is enabled.)
2680 */
2681static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
2682    ScopedJniThreadState ts(env);
2683
2684    /* create an instance of java.nio.ReadWriteDirectByteBuffer */
2685    ClassObject* bufferClazz = gDvm.classJavaNioReadWriteDirectByteBuffer;
2686    if (!dvmIsClassInitialized(bufferClazz) && !dvmInitClass(bufferClazz)) {
2687        return NULL;
2688    }
2689    Object* newObj = dvmAllocObject(bufferClazz, ALLOC_DONT_TRACK);
2690    if (newObj == NULL) {
2691        return NULL;
2692    }
2693    /* call the constructor */
2694    jobject result = addLocalReference(ts.self(), newObj);
2695    JValue unused;
2696    dvmCallMethod(ts.self(), gDvm.methJavaNioReadWriteDirectByteBuffer_init,
2697            newObj, &unused, (jint) address, (jint) capacity);
2698    if (dvmGetException(ts.self()) != NULL) {
2699        deleteLocalReference(ts.self(), result);
2700        return NULL;
2701    }
2702    return result;
2703}
2704
2705/*
2706 * Get the starting address of the buffer for the specified java.nio.Buffer.
2707 *
2708 * If this is not a "direct" buffer, we return NULL.
2709 */
2710static void* GetDirectBufferAddress(JNIEnv* env, jobject jbuf) {
2711    ScopedJniThreadState ts(env);
2712
2713    // All Buffer objects have an effectiveDirectAddress field.
2714    Object* bufObj = dvmDecodeIndirectRef(ts.self(), jbuf);
2715    return (void*) dvmGetFieldInt(bufObj, gDvm.offJavaNioBuffer_effectiveDirectAddress);
2716}
2717
2718/*
2719 * Get the capacity of the buffer for the specified java.nio.Buffer.
2720 *
2721 * Returns -1 if the object is not a direct buffer.  (We actually skip
2722 * this check, since it's expensive to determine, and just return the
2723 * capacity regardless.)
2724 */
2725static jlong GetDirectBufferCapacity(JNIEnv* env, jobject jbuf) {
2726    ScopedJniThreadState ts(env);
2727
2728    /*
2729     * The capacity is always in the Buffer.capacity field.
2730     *
2731     * (The "check" version should verify that this is actually a Buffer,
2732     * but we're not required to do so here.)
2733     */
2734    Object* buf = dvmDecodeIndirectRef(ts.self(), jbuf);
2735    return dvmGetFieldInt(buf, gDvm.offJavaNioBuffer_capacity);
2736}
2737
2738
2739/*
2740 * ===========================================================================
2741 *      JNI invocation functions
2742 * ===========================================================================
2743 */
2744
2745/*
2746 * Handle AttachCurrentThread{AsDaemon}.
2747 *
2748 * We need to make sure the VM is actually running.  For example, if we start
2749 * up, issue an Attach, and the VM exits almost immediately, by the time the
2750 * attaching happens the VM could already be shutting down.
2751 *
2752 * It's hard to avoid a race condition here because we don't want to hold
2753 * a lock across the entire operation.  What we can do is temporarily
2754 * increment the thread count to prevent a VM exit.
2755 *
2756 * This could potentially still have problems if a daemon thread calls here
2757 * while the VM is shutting down.  dvmThreadSelf() will work, since it just
2758 * uses pthread TLS, but dereferencing "vm" could fail.  Such is life when
2759 * you shut down a VM while threads are still running inside it.
2760 *
2761 * Remember that some code may call this as a way to find the per-thread
2762 * JNIEnv pointer.  Don't do excess work for that case.
2763 */
2764static jint attachThread(JavaVM* vm, JNIEnv** p_env, void* thr_args, bool isDaemon) {
2765    JavaVMAttachArgs* args = (JavaVMAttachArgs*) thr_args;
2766
2767    /*
2768     * Return immediately if we're already one with the VM.
2769     */
2770    Thread* self = dvmThreadSelf();
2771    if (self != NULL) {
2772        *p_env = self->jniEnv;
2773        return JNI_OK;
2774    }
2775
2776    /*
2777     * No threads allowed in zygote mode.
2778     */
2779    if (gDvm.zygote) {
2780        return JNI_ERR;
2781    }
2782
2783    /* increment the count to keep the VM from bailing while we run */
2784    dvmLockThreadList(NULL);
2785    if (gDvm.nonDaemonThreadCount == 0) {
2786        // dead or dying
2787        ALOGV("Refusing to attach thread '%s' -- VM is shutting down",
2788            (thr_args == NULL) ? "(unknown)" : args->name);
2789        dvmUnlockThreadList();
2790        return JNI_ERR;
2791    }
2792    gDvm.nonDaemonThreadCount++;
2793    dvmUnlockThreadList();
2794
2795    /* tweak the JavaVMAttachArgs as needed */
2796    JavaVMAttachArgs argsCopy;
2797    if (args == NULL) {
2798        /* allow the v1.1 calling convention */
2799        argsCopy.version = JNI_VERSION_1_2;
2800        argsCopy.name = NULL;
2801        argsCopy.group = (jobject) dvmGetMainThreadGroup();
2802    } else {
2803        assert(args->version >= JNI_VERSION_1_2);
2804
2805        argsCopy.version = args->version;
2806        argsCopy.name = args->name;
2807        if (args->group != NULL) {
2808            argsCopy.group = (jobject) dvmDecodeIndirectRef(NULL, args->group);
2809        } else {
2810            argsCopy.group = (jobject) dvmGetMainThreadGroup();
2811        }
2812    }
2813
2814    bool result = dvmAttachCurrentThread(&argsCopy, isDaemon);
2815
2816    /* restore the count */
2817    dvmLockThreadList(NULL);
2818    gDvm.nonDaemonThreadCount--;
2819    dvmUnlockThreadList();
2820
2821    /*
2822     * Change the status to indicate that we're out in native code.  This
2823     * call is not guarded with state-change macros, so we have to do it
2824     * by hand.
2825     */
2826    if (result) {
2827        self = dvmThreadSelf();
2828        assert(self != NULL);
2829        dvmChangeStatus(self, THREAD_NATIVE);
2830        *p_env = self->jniEnv;
2831        return JNI_OK;
2832    } else {
2833        return JNI_ERR;
2834    }
2835}
2836
2837/*
2838 * Attach the current thread to the VM.  If the thread is already attached,
2839 * this is a no-op.
2840 */
2841static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
2842    return attachThread(vm, p_env, thr_args, false);
2843}
2844
2845/*
2846 * Like AttachCurrentThread, but set the "daemon" flag.
2847 */
2848static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args)
2849{
2850    return attachThread(vm, p_env, thr_args, true);
2851}
2852
2853/*
2854 * Dissociate the current thread from the VM.
2855 */
2856static jint DetachCurrentThread(JavaVM* vm) {
2857    Thread* self = dvmThreadSelf();
2858    if (self == NULL) {
2859        /* not attached, can't do anything */
2860        return JNI_ERR;
2861    }
2862
2863    /* switch to "running" to check for suspension */
2864    dvmChangeStatus(self, THREAD_RUNNING);
2865
2866    /* detach the thread */
2867    dvmDetachCurrentThread();
2868
2869    /* (no need to change status back -- we have no status) */
2870    return JNI_OK;
2871}
2872
2873/*
2874 * If current thread is attached to VM, return the associated JNIEnv.
2875 * Otherwise, stuff NULL in and return JNI_EDETACHED.
2876 *
2877 * JVMTI overloads this by specifying a magic value for "version", so we
2878 * do want to check that here.
2879 */
2880static jint GetEnv(JavaVM* vm, void** env, jint version) {
2881    Thread* self = dvmThreadSelf();
2882
2883    if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6) {
2884        return JNI_EVERSION;
2885    }
2886
2887    if (self == NULL) {
2888        *env = NULL;
2889    } else {
2890        /* TODO: status change is probably unnecessary */
2891        dvmChangeStatus(self, THREAD_RUNNING);
2892        *env = (void*) dvmGetThreadJNIEnv(self);
2893        dvmChangeStatus(self, THREAD_NATIVE);
2894    }
2895    return (*env != NULL) ? JNI_OK : JNI_EDETACHED;
2896}
2897
2898/*
2899 * Destroy the VM.  This may be called from any thread.
2900 *
2901 * If the current thread is attached, wait until the current thread is
2902 * the only non-daemon user-level thread.  If the current thread is not
2903 * attached, we attach it and do the processing as usual.  (If the attach
2904 * fails, it's probably because all the non-daemon threads have already
2905 * exited and the VM doesn't want to let us back in.)
2906 *
2907 * TODO: we don't really deal with the situation where more than one thread
2908 * has called here.  One thread wins, the other stays trapped waiting on
2909 * the condition variable forever.  Not sure this situation is interesting
2910 * in real life.
2911 */
2912static jint DestroyJavaVM(JavaVM* vm) {
2913    JavaVMExt* ext = (JavaVMExt*) vm;
2914    if (ext == NULL) {
2915        return JNI_ERR;
2916    }
2917
2918    if (gDvm.verboseShutdown) {
2919        ALOGD("DestroyJavaVM waiting for non-daemon threads to exit");
2920    }
2921
2922    /*
2923     * Sleep on a condition variable until it's okay to exit.
2924     */
2925    Thread* self = dvmThreadSelf();
2926    if (self == NULL) {
2927        JNIEnv* tmpEnv;
2928        if (AttachCurrentThread(vm, &tmpEnv, NULL) != JNI_OK) {
2929            ALOGV("Unable to reattach main for Destroy; assuming VM is shutting down (count=%d)",
2930                gDvm.nonDaemonThreadCount);
2931            goto shutdown;
2932        } else {
2933            ALOGV("Attached to wait for shutdown in Destroy");
2934        }
2935    }
2936    dvmChangeStatus(self, THREAD_VMWAIT);
2937
2938    dvmLockThreadList(self);
2939    gDvm.nonDaemonThreadCount--;    // remove current thread from count
2940
2941    while (gDvm.nonDaemonThreadCount > 0) {
2942        pthread_cond_wait(&gDvm.vmExitCond, &gDvm.threadListLock);
2943    }
2944
2945    dvmUnlockThreadList();
2946    self = NULL;
2947
2948shutdown:
2949    // TODO: call System.exit() to run any registered shutdown hooks
2950    // (this may not return -- figure out how this should work)
2951
2952    if (gDvm.verboseShutdown) {
2953        ALOGD("DestroyJavaVM shutting VM down");
2954    }
2955    dvmShutdown();
2956
2957    // TODO - free resources associated with JNI-attached daemon threads
2958    free(ext->envList);
2959    free(ext);
2960
2961    return JNI_OK;
2962}
2963
2964
2965/*
2966 * ===========================================================================
2967 *      Function tables
2968 * ===========================================================================
2969 */
2970
2971static const struct JNINativeInterface gNativeInterface = {
2972    NULL,
2973    NULL,
2974    NULL,
2975    NULL,
2976
2977    GetVersion,
2978
2979    DefineClass,
2980    FindClass,
2981
2982    FromReflectedMethod,
2983    FromReflectedField,
2984    ToReflectedMethod,
2985
2986    GetSuperclass,
2987    IsAssignableFrom,
2988
2989    ToReflectedField,
2990
2991    Throw,
2992    ThrowNew,
2993    ExceptionOccurred,
2994    ExceptionDescribe,
2995    ExceptionClear,
2996    FatalError,
2997
2998    PushLocalFrame,
2999    PopLocalFrame,
3000
3001    NewGlobalRef,
3002    DeleteGlobalRef,
3003    DeleteLocalRef,
3004    IsSameObject,
3005    NewLocalRef,
3006    EnsureLocalCapacity,
3007
3008    AllocObject,
3009    NewObject,
3010    NewObjectV,
3011    NewObjectA,
3012
3013    GetObjectClass,
3014    IsInstanceOf,
3015
3016    GetMethodID,
3017
3018    CallObjectMethod,
3019    CallObjectMethodV,
3020    CallObjectMethodA,
3021    CallBooleanMethod,
3022    CallBooleanMethodV,
3023    CallBooleanMethodA,
3024    CallByteMethod,
3025    CallByteMethodV,
3026    CallByteMethodA,
3027    CallCharMethod,
3028    CallCharMethodV,
3029    CallCharMethodA,
3030    CallShortMethod,
3031    CallShortMethodV,
3032    CallShortMethodA,
3033    CallIntMethod,
3034    CallIntMethodV,
3035    CallIntMethodA,
3036    CallLongMethod,
3037    CallLongMethodV,
3038    CallLongMethodA,
3039    CallFloatMethod,
3040    CallFloatMethodV,
3041    CallFloatMethodA,
3042    CallDoubleMethod,
3043    CallDoubleMethodV,
3044    CallDoubleMethodA,
3045    CallVoidMethod,
3046    CallVoidMethodV,
3047    CallVoidMethodA,
3048
3049    CallNonvirtualObjectMethod,
3050    CallNonvirtualObjectMethodV,
3051    CallNonvirtualObjectMethodA,
3052    CallNonvirtualBooleanMethod,
3053    CallNonvirtualBooleanMethodV,
3054    CallNonvirtualBooleanMethodA,
3055    CallNonvirtualByteMethod,
3056    CallNonvirtualByteMethodV,
3057    CallNonvirtualByteMethodA,
3058    CallNonvirtualCharMethod,
3059    CallNonvirtualCharMethodV,
3060    CallNonvirtualCharMethodA,
3061    CallNonvirtualShortMethod,
3062    CallNonvirtualShortMethodV,
3063    CallNonvirtualShortMethodA,
3064    CallNonvirtualIntMethod,
3065    CallNonvirtualIntMethodV,
3066    CallNonvirtualIntMethodA,
3067    CallNonvirtualLongMethod,
3068    CallNonvirtualLongMethodV,
3069    CallNonvirtualLongMethodA,
3070    CallNonvirtualFloatMethod,
3071    CallNonvirtualFloatMethodV,
3072    CallNonvirtualFloatMethodA,
3073    CallNonvirtualDoubleMethod,
3074    CallNonvirtualDoubleMethodV,
3075    CallNonvirtualDoubleMethodA,
3076    CallNonvirtualVoidMethod,
3077    CallNonvirtualVoidMethodV,
3078    CallNonvirtualVoidMethodA,
3079
3080    GetFieldID,
3081
3082    GetObjectField,
3083    GetBooleanField,
3084    GetByteField,
3085    GetCharField,
3086    GetShortField,
3087    GetIntField,
3088    GetLongField,
3089    GetFloatField,
3090    GetDoubleField,
3091    SetObjectField,
3092    SetBooleanField,
3093    SetByteField,
3094    SetCharField,
3095    SetShortField,
3096    SetIntField,
3097    SetLongField,
3098    SetFloatField,
3099    SetDoubleField,
3100
3101    GetStaticMethodID,
3102
3103    CallStaticObjectMethod,
3104    CallStaticObjectMethodV,
3105    CallStaticObjectMethodA,
3106    CallStaticBooleanMethod,
3107    CallStaticBooleanMethodV,
3108    CallStaticBooleanMethodA,
3109    CallStaticByteMethod,
3110    CallStaticByteMethodV,
3111    CallStaticByteMethodA,
3112    CallStaticCharMethod,
3113    CallStaticCharMethodV,
3114    CallStaticCharMethodA,
3115    CallStaticShortMethod,
3116    CallStaticShortMethodV,
3117    CallStaticShortMethodA,
3118    CallStaticIntMethod,
3119    CallStaticIntMethodV,
3120    CallStaticIntMethodA,
3121    CallStaticLongMethod,
3122    CallStaticLongMethodV,
3123    CallStaticLongMethodA,
3124    CallStaticFloatMethod,
3125    CallStaticFloatMethodV,
3126    CallStaticFloatMethodA,
3127    CallStaticDoubleMethod,
3128    CallStaticDoubleMethodV,
3129    CallStaticDoubleMethodA,
3130    CallStaticVoidMethod,
3131    CallStaticVoidMethodV,
3132    CallStaticVoidMethodA,
3133
3134    GetStaticFieldID,
3135
3136    GetStaticObjectField,
3137    GetStaticBooleanField,
3138    GetStaticByteField,
3139    GetStaticCharField,
3140    GetStaticShortField,
3141    GetStaticIntField,
3142    GetStaticLongField,
3143    GetStaticFloatField,
3144    GetStaticDoubleField,
3145
3146    SetStaticObjectField,
3147    SetStaticBooleanField,
3148    SetStaticByteField,
3149    SetStaticCharField,
3150    SetStaticShortField,
3151    SetStaticIntField,
3152    SetStaticLongField,
3153    SetStaticFloatField,
3154    SetStaticDoubleField,
3155
3156    NewString,
3157
3158    GetStringLength,
3159    GetStringChars,
3160    ReleaseStringChars,
3161
3162    NewStringUTF,
3163    GetStringUTFLength,
3164    GetStringUTFChars,
3165    ReleaseStringUTFChars,
3166
3167    GetArrayLength,
3168    NewObjectArray,
3169    GetObjectArrayElement,
3170    SetObjectArrayElement,
3171
3172    NewBooleanArray,
3173    NewByteArray,
3174    NewCharArray,
3175    NewShortArray,
3176    NewIntArray,
3177    NewLongArray,
3178    NewFloatArray,
3179    NewDoubleArray,
3180
3181    GetBooleanArrayElements,
3182    GetByteArrayElements,
3183    GetCharArrayElements,
3184    GetShortArrayElements,
3185    GetIntArrayElements,
3186    GetLongArrayElements,
3187    GetFloatArrayElements,
3188    GetDoubleArrayElements,
3189
3190    ReleaseBooleanArrayElements,
3191    ReleaseByteArrayElements,
3192    ReleaseCharArrayElements,
3193    ReleaseShortArrayElements,
3194    ReleaseIntArrayElements,
3195    ReleaseLongArrayElements,
3196    ReleaseFloatArrayElements,
3197    ReleaseDoubleArrayElements,
3198
3199    GetBooleanArrayRegion,
3200    GetByteArrayRegion,
3201    GetCharArrayRegion,
3202    GetShortArrayRegion,
3203    GetIntArrayRegion,
3204    GetLongArrayRegion,
3205    GetFloatArrayRegion,
3206    GetDoubleArrayRegion,
3207    SetBooleanArrayRegion,
3208    SetByteArrayRegion,
3209    SetCharArrayRegion,
3210    SetShortArrayRegion,
3211    SetIntArrayRegion,
3212    SetLongArrayRegion,
3213    SetFloatArrayRegion,
3214    SetDoubleArrayRegion,
3215
3216    RegisterNatives,
3217    UnregisterNatives,
3218
3219    MonitorEnter,
3220    MonitorExit,
3221
3222    GetJavaVM,
3223
3224    GetStringRegion,
3225    GetStringUTFRegion,
3226
3227    GetPrimitiveArrayCritical,
3228    ReleasePrimitiveArrayCritical,
3229
3230    GetStringCritical,
3231    ReleaseStringCritical,
3232
3233    NewWeakGlobalRef,
3234    DeleteWeakGlobalRef,
3235
3236    ExceptionCheck,
3237
3238    NewDirectByteBuffer,
3239    GetDirectBufferAddress,
3240    GetDirectBufferCapacity,
3241
3242    GetObjectRefType
3243};
3244
3245static const struct JNIInvokeInterface gInvokeInterface = {
3246    NULL,
3247    NULL,
3248    NULL,
3249
3250    DestroyJavaVM,
3251    AttachCurrentThread,
3252    DetachCurrentThread,
3253
3254    GetEnv,
3255
3256    AttachCurrentThreadAsDaemon,
3257};
3258
3259/*
3260 * ===========================================================================
3261 *      VM/Env creation
3262 * ===========================================================================
3263 */
3264
3265/*
3266 * Create a new JNIEnv struct and add it to the VM's list.
3267 *
3268 * "self" will be NULL for the main thread, since the VM hasn't started
3269 * yet; the value will be filled in later.
3270 */
3271JNIEnv* dvmCreateJNIEnv(Thread* self) {
3272    JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
3273
3274    //if (self != NULL)
3275    //    ALOGI("Ent CreateJNIEnv: threadid=%d %p", self->threadId, self);
3276
3277    assert(vm != NULL);
3278
3279    JNIEnvExt* newEnv = (JNIEnvExt*) calloc(1, sizeof(JNIEnvExt));
3280    newEnv->funcTable = &gNativeInterface;
3281    if (self != NULL) {
3282        dvmSetJniEnvThreadId((JNIEnv*) newEnv, self);
3283        assert(newEnv->envThreadId != 0);
3284    } else {
3285        /* make it obvious if we fail to initialize these later */
3286        newEnv->envThreadId = 0x77777775;
3287        newEnv->self = (Thread*) 0x77777779;
3288    }
3289    if (gDvmJni.useCheckJni) {
3290        dvmUseCheckedJniEnv(newEnv);
3291    }
3292
3293    ScopedPthreadMutexLock lock(&vm->envListLock);
3294
3295    /* insert at head of list */
3296    newEnv->next = vm->envList;
3297    assert(newEnv->prev == NULL);
3298    if (vm->envList == NULL) {
3299        // rare, but possible
3300        vm->envList = newEnv;
3301    } else {
3302        vm->envList->prev = newEnv;
3303    }
3304    vm->envList = newEnv;
3305
3306    //if (self != NULL)
3307    //    ALOGI("Xit CreateJNIEnv: threadid=%d %p", self->threadId, self);
3308    return (JNIEnv*) newEnv;
3309}
3310
3311/*
3312 * Remove a JNIEnv struct from the list and free it.
3313 */
3314void dvmDestroyJNIEnv(JNIEnv* env) {
3315    if (env == NULL) {
3316        return;
3317    }
3318
3319    //ALOGI("Ent DestroyJNIEnv: threadid=%d %p", self->threadId, self);
3320
3321    JNIEnvExt* extEnv = (JNIEnvExt*) env;
3322    JavaVMExt* vm = (JavaVMExt*) gDvmJni.jniVm;
3323
3324    ScopedPthreadMutexLock lock(&vm->envListLock);
3325
3326    if (extEnv == vm->envList) {
3327        assert(extEnv->prev == NULL);
3328        vm->envList = extEnv->next;
3329    } else {
3330        assert(extEnv->prev != NULL);
3331        extEnv->prev->next = extEnv->next;
3332    }
3333    if (extEnv->next != NULL) {
3334        extEnv->next->prev = extEnv->prev;
3335    }
3336
3337    free(env);
3338    //ALOGI("Xit DestroyJNIEnv: threadid=%d %p", self->threadId, self);
3339}
3340
3341/*
3342 * Enable "checked JNI" after the VM has partially started.  This must
3343 * only be called in "zygote" mode, when we have one thread running.
3344 *
3345 * This doesn't attempt to rewrite the JNI call bridge associated with
3346 * native methods, so we won't get those checks for any methods that have
3347 * already been resolved.
3348 */
3349void dvmLateEnableCheckedJni() {
3350    JNIEnvExt* extEnv = dvmGetJNIEnvForThread();
3351    if (extEnv == NULL) {
3352        LOGE("dvmLateEnableCheckedJni: thread has no JNIEnv");
3353        return;
3354    }
3355    JavaVMExt* extVm = (JavaVMExt*) gDvmJni.jniVm;
3356    assert(extVm != NULL);
3357
3358    if (!gDvmJni.useCheckJni) {
3359        ALOGD("Late-enabling CheckJNI");
3360        dvmUseCheckedJniVm(extVm);
3361        dvmUseCheckedJniEnv(extEnv);
3362    } else {
3363        ALOGD("Not late-enabling CheckJNI (already on)");
3364    }
3365}
3366
3367/*
3368 * Not supported.
3369 */
3370jint JNI_GetDefaultJavaVMInitArgs(void* vm_args) {
3371    return JNI_ERR;
3372}
3373
3374/*
3375 * Return a buffer full of created VMs.
3376 *
3377 * We always have zero or one.
3378 */
3379jint JNI_GetCreatedJavaVMs(JavaVM** vmBuf, jsize bufLen, jsize* nVMs) {
3380    if (gDvmJni.jniVm != NULL) {
3381        *nVMs = 1;
3382        if (bufLen > 0) {
3383            *vmBuf++ = gDvmJni.jniVm;
3384        }
3385    } else {
3386        *nVMs = 0;
3387    }
3388    return JNI_OK;
3389}
3390
3391/*
3392 * Create a new VM instance.
3393 *
3394 * The current thread becomes the main VM thread.  We return immediately,
3395 * which effectively means the caller is executing in a native method.
3396 */
3397jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
3398    const JavaVMInitArgs* args = (JavaVMInitArgs*) vm_args;
3399    if (args->version < JNI_VERSION_1_2) {
3400        return JNI_EVERSION;
3401    }
3402
3403    // TODO: don't allow creation of multiple VMs -- one per customer for now
3404
3405    /* zero globals; not strictly necessary the first time a VM is started */
3406    memset(&gDvm, 0, sizeof(gDvm));
3407
3408    /*
3409     * Set up structures for JNIEnv and VM.
3410     */
3411    JavaVMExt* pVM = (JavaVMExt*) malloc(sizeof(JavaVMExt));
3412    memset(pVM, 0, sizeof(JavaVMExt));
3413    pVM->funcTable = &gInvokeInterface;
3414    pVM->envList = NULL;
3415    dvmInitMutex(&pVM->envListLock);
3416
3417    UniquePtr<const char*[]> argv(new const char*[args->nOptions]);
3418    memset(argv.get(), 0, sizeof(char*) * (args->nOptions));
3419
3420    /*
3421     * Convert JNI args to argv.
3422     *
3423     * We have to pull out vfprintf/exit/abort, because they use the
3424     * "extraInfo" field to pass function pointer "hooks" in.  We also
3425     * look for the -Xcheck:jni stuff here.
3426     */
3427    int argc = 0;
3428    for (int i = 0; i < args->nOptions; i++) {
3429        const char* optStr = args->options[i].optionString;
3430        if (optStr == NULL) {
3431            dvmFprintf(stderr, "ERROR: CreateJavaVM failed: argument %d was NULL\n", i);
3432            return JNI_ERR;
3433        } else if (strcmp(optStr, "vfprintf") == 0) {
3434            gDvm.vfprintfHook = (int (*)(FILE *, const char*, va_list))args->options[i].extraInfo;
3435        } else if (strcmp(optStr, "exit") == 0) {
3436            gDvm.exitHook = (void (*)(int)) args->options[i].extraInfo;
3437        } else if (strcmp(optStr, "abort") == 0) {
3438            gDvm.abortHook = (void (*)(void))args->options[i].extraInfo;
3439        } else if (strcmp(optStr, "sensitiveThread") == 0) {
3440            gDvm.isSensitiveThreadHook = (bool (*)(void))args->options[i].extraInfo;
3441        } else if (strcmp(optStr, "-Xcheck:jni") == 0) {
3442            gDvmJni.useCheckJni = true;
3443        } else if (strncmp(optStr, "-Xjniopts:", 10) == 0) {
3444            char* jniOpts = strdup(optStr + 10);
3445            size_t jniOptCount = 1;
3446            for (char* p = jniOpts; *p != 0; ++p) {
3447                if (*p == ',') {
3448                    ++jniOptCount;
3449                    *p = 0;
3450                }
3451            }
3452            char* jniOpt = jniOpts;
3453            for (size_t i = 0; i < jniOptCount; ++i) {
3454                if (strcmp(jniOpt, "warnonly") == 0) {
3455                    gDvmJni.warnOnly = true;
3456                } else if (strcmp(jniOpt, "forcecopy") == 0) {
3457                    gDvmJni.forceCopy = true;
3458                } else if (strcmp(jniOpt, "logThirdPartyJni") == 0) {
3459                    gDvmJni.logThirdPartyJni = true;
3460                } else {
3461                    dvmFprintf(stderr, "ERROR: CreateJavaVM failed: unknown -Xjniopts option '%s'\n",
3462                            jniOpt);
3463                    return JNI_ERR;
3464                }
3465                jniOpt += strlen(jniOpt) + 1;
3466            }
3467            free(jniOpts);
3468        } else {
3469            /* regular option */
3470            argv[argc++] = optStr;
3471        }
3472    }
3473
3474    if (gDvmJni.useCheckJni) {
3475        dvmUseCheckedJniVm(pVM);
3476    }
3477
3478    if (gDvmJni.jniVm != NULL) {
3479        dvmFprintf(stderr, "ERROR: Dalvik only supports one VM per process\n");
3480        return JNI_ERR;
3481    }
3482    gDvmJni.jniVm = (JavaVM*) pVM;
3483
3484    /*
3485     * Create a JNIEnv for the main thread.  We need to have something set up
3486     * here because some of the class initialization we do when starting
3487     * up the VM will call into native code.
3488     */
3489    JNIEnvExt* pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);
3490
3491    /* Initialize VM. */
3492    gDvm.initializing = true;
3493    std::string status =
3494            dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);
3495    gDvm.initializing = false;
3496
3497    if (!status.empty()) {
3498        free(pEnv);
3499        free(pVM);
3500        ALOGW("CreateJavaVM failed: %s", status.c_str());
3501        return JNI_ERR;
3502    }
3503
3504    /*
3505     * Success!  Return stuff to caller.
3506     */
3507    dvmChangeStatus(NULL, THREAD_NATIVE);
3508    *p_env = (JNIEnv*) pEnv;
3509    *p_vm = (JavaVM*) pVM;
3510    ALOGV("CreateJavaVM succeeded");
3511    return JNI_OK;
3512}
3513