CheckJni.cpp revision a6e94ff55517438569d207e3ed552c8c127bcac9
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 * Support for -Xcheck:jni (the "careful" version of the JNI interfaces).
19 *
20 * We want to verify types, make sure class and field IDs are valid, and
21 * ensure that JNI's semantic expectations are being met.  JNI seems to
22 * be relatively lax when it comes to requirements for permission checks,
23 * e.g. access to private methods is generally allowed from anywhere.
24 */
25
26#include "Dalvik.h"
27#include "JniInternal.h"
28
29#include <sys/mman.h>
30#include <zlib.h>
31
32/*
33 * Abort if we are configured to bail out on JNI warnings.
34 */
35static void abortMaybe() {
36    if (!gDvmJni.warnOnly) {
37        dvmDumpThread(dvmThreadSelf(), false);
38        dvmAbort();
39    }
40}
41
42/*
43 * ===========================================================================
44 *      JNI call bridge wrapper
45 * ===========================================================================
46 */
47
48/*
49 * Check the result of a native method call that returns an object reference.
50 *
51 * The primary goal here is to verify that native code is returning the
52 * correct type of object.  If it's declared to return a String but actually
53 * returns a byte array, things will fail in strange ways later on.
54 *
55 * This can be a fairly expensive operation, since we have to look up the
56 * return type class by name in method->clazz' class loader.  We take a
57 * shortcut here and allow the call to succeed if the descriptor strings
58 * match.  This will allow some false-positives when a class is redefined
59 * by a class loader, but that's rare enough that it doesn't seem worth
60 * testing for.
61 *
62 * At this point, pResult->l has already been converted to an object pointer.
63 */
64static void checkCallResultCommon(const u4* args, const JValue* pResult,
65        const Method* method, Thread* self)
66{
67    assert(pResult->l != NULL);
68    const Object* resultObj = (const Object*) pResult->l;
69
70    if (resultObj == kInvalidIndirectRefObject) {
71        LOGW("JNI WARNING: invalid reference returned from native code");
72        const Method* method = dvmGetCurrentJNIMethod();
73        char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
74        LOGW("             in %s.%s:%s", method->clazz->descriptor, method->name, desc);
75        free(desc);
76        abortMaybe();
77        return;
78    }
79
80    ClassObject* objClazz = resultObj->clazz;
81
82    /*
83     * Make sure that pResult->l is an instance of the type this
84     * method was expected to return.
85     */
86    const char* declType = dexProtoGetReturnType(&method->prototype);
87    const char* objType = objClazz->descriptor;
88    if (strcmp(declType, objType) == 0) {
89        /* names match; ignore class loader issues and allow it */
90        LOGV("Check %s.%s: %s io %s (FAST-OK)",
91            method->clazz->descriptor, method->name, objType, declType);
92    } else {
93        /*
94         * Names didn't match.  We need to resolve declType in the context
95         * of method->clazz->classLoader, and compare the class objects
96         * for equality.
97         *
98         * Since we're returning an instance of declType, it's safe to
99         * assume that it has been loaded and initialized (or, for the case
100         * of an array, generated).  However, the current class loader may
101         * not be listed as an initiating loader, so we can't just look for
102         * it in the loaded-classes list.
103         */
104        ClassObject* declClazz = dvmFindClassNoInit(declType, method->clazz->classLoader);
105        if (declClazz == NULL) {
106            LOGW("JNI WARNING: method declared to return '%s' returned '%s'",
107                declType, objType);
108            LOGW("             failed in %s.%s ('%s' not found)",
109                method->clazz->descriptor, method->name, declType);
110            abortMaybe();
111            return;
112        }
113        if (!dvmInstanceof(objClazz, declClazz)) {
114            LOGW("JNI WARNING: method declared to return '%s' returned '%s'",
115                declType, objType);
116            LOGW("             failed in %s.%s",
117                method->clazz->descriptor, method->name);
118            abortMaybe();
119            return;
120        } else {
121            LOGV("Check %s.%s: %s io %s (SLOW-OK)",
122                method->clazz->descriptor, method->name, objType, declType);
123        }
124    }
125}
126
127/*
128 * Determine if we need to check the return type coming out of the call.
129 *
130 * (We don't simply do this at the top of checkCallResultCommon() because
131 * this is on the critical path for native method calls.)
132 */
133static inline bool callNeedsCheck(const u4* args, JValue* pResult,
134    const Method* method, Thread* self)
135{
136    return (method->shorty[0] == 'L' && !dvmCheckException(self) && pResult->l != NULL);
137}
138
139/*
140 * Check a call into native code.
141 */
142void dvmCheckCallJNIMethod(const u4* args, JValue* pResult,
143    const Method* method, Thread* self)
144{
145    dvmCallJNIMethod(args, pResult, method, self);
146    if (callNeedsCheck(args, pResult, method, self)) {
147        checkCallResultCommon(args, pResult, method, self);
148    }
149}
150
151/*
152 * ===========================================================================
153 *      JNI function helpers
154 * ===========================================================================
155 */
156
157static inline const JNINativeInterface* baseEnv(JNIEnv* env) {
158    return ((JNIEnvExt*) env)->baseFuncTable;
159}
160
161static inline const JNIInvokeInterface* baseVm(JavaVM* vm) {
162    return ((JavaVMExt*) vm)->baseFuncTable;
163}
164
165class ScopedJniThreadState {
166public:
167    explicit ScopedJniThreadState(JNIEnv* env) {
168        dvmChangeStatus(NULL, THREAD_RUNNING);
169    }
170
171    ~ScopedJniThreadState() {
172        dvmChangeStatus(NULL, THREAD_NATIVE);
173    }
174
175private:
176    // Disallow copy and assignment.
177    ScopedJniThreadState(const ScopedJniThreadState&);
178    void operator=(const ScopedJniThreadState&);
179};
180
181/*
182 * Flags passed into ScopedCheck.
183 */
184#define kFlag_Default       0x0000
185
186#define kFlag_CritBad       0x0000      /* calling while in critical is bad */
187#define kFlag_CritOkay      0x0001      /* ...okay */
188#define kFlag_CritGet       0x0002      /* this is a critical "get" */
189#define kFlag_CritRelease   0x0003      /* this is a critical "release" */
190#define kFlag_CritMask      0x0003      /* bit mask to get "crit" value */
191
192#define kFlag_ExcepBad      0x0000      /* raised exceptions are bad */
193#define kFlag_ExcepOkay     0x0004      /* ...okay */
194
195#define kFlag_Release       0x0010      /* are we in a non-critical release function? */
196#define kFlag_NullableUtf   0x0020      /* are our UTF parameters nullable? */
197
198#define kFlag_Invocation    0x8000      /* Part of the invocation interface (JavaVM*) */
199
200static const char* indirectRefKindName(IndirectRef iref)
201{
202    return indirectRefKindToString(indirectRefKind(iref));
203}
204
205class ScopedCheck {
206public:
207    // For JNIEnv* functions.
208    explicit ScopedCheck(JNIEnv* env, int flags, const char* functionName) {
209        init(env, flags, functionName, true);
210        checkThread(flags);
211    }
212
213    // For JavaVM* functions.
214    explicit ScopedCheck(bool hasMethod, const char* functionName) {
215        init(NULL, kFlag_Invocation, functionName, hasMethod);
216    }
217
218    /*
219     * In some circumstances the VM will screen class names, but it doesn't
220     * for class lookup.  When things get bounced through a class loader, they
221     * can actually get normalized a couple of times; as a result, passing in
222     * a class name like "java.lang.Thread" instead of "java/lang/Thread" will
223     * work in some circumstances.
224     *
225     * This is incorrect and could cause strange behavior or compatibility
226     * problems, so we want to screen that out here.
227     *
228     * We expect "fully-qualified" class names, like "java/lang/Thread" or
229     * "[Ljava/lang/Object;".
230     */
231    void checkClassName(const char* className) {
232        if (!dexIsValidClassName(className, false)) {
233            LOGW("JNI WARNING: illegal class name '%s' (%s)", className, mFunctionName);
234            LOGW("             (should be formed like 'dalvik/system/DexFile')");
235            LOGW("             or '[Ldalvik/system/DexFile;' or '[[B')");
236            abortMaybe();
237        }
238    }
239
240    /*
241     * Verify that the field is of the appropriate type.  If the field has an
242     * object type, "jobj" is the object we're trying to assign into it.
243     *
244     * Works for both static and instance fields.
245     */
246    void checkFieldType(jobject jobj, jfieldID fieldID, PrimitiveType prim, bool isStatic) {
247        if (fieldID == NULL) {
248            LOGW("JNI WARNING: null field ID");
249            showLocation();
250            abortMaybe();
251        }
252
253        bool printWarn = false;
254        Field* field = (Field*) fieldID;
255        if ((field->signature[0] == 'L' || field->signature[0] == '[') && jobj != NULL) {
256            ScopedJniThreadState ts(mEnv);
257            Object* obj = dvmDecodeIndirectRef(mEnv, jobj);
258            /*
259             * If jobj is a weak global ref whose referent has been cleared,
260             * obj will be NULL.  Otherwise, obj should always be non-NULL
261             * and valid.
262             */
263            if (obj != NULL && !dvmIsValidObject(obj)) {
264                LOGW("JNI WARNING: field operation on invalid %s reference (%p)",
265                        indirectRefKindName(jobj), jobj);
266                printWarn = true;
267            } else {
268                ClassObject* fieldClass = dvmFindLoadedClass(field->signature);
269                ClassObject* objClass = obj->clazz;
270
271                assert(fieldClass != NULL);
272                assert(objClass != NULL);
273
274                if (!dvmInstanceof(objClass, fieldClass)) {
275                    LOGW("JNI WARNING: set field '%s' expected type %s, got %s",
276                            field->name, field->signature, objClass->descriptor);
277                    printWarn = true;
278                }
279            }
280        } else if (dexGetPrimitiveTypeFromDescriptorChar(field->signature[0]) != prim) {
281            LOGW("JNI WARNING: set field '%s' expected type %s, got %s",
282                    field->name, field->signature, primitiveTypeToName(prim));
283            printWarn = true;
284        } else if (isStatic && !dvmIsStaticField(field)) {
285            if (isStatic) {
286                LOGW("JNI WARNING: accessing non-static field %s as static", field->name);
287            } else {
288                LOGW("JNI WARNING: accessing static field %s as non-static", field->name);
289            }
290            printWarn = true;
291        }
292
293        if (printWarn) {
294            showLocation();
295            abortMaybe();
296        }
297    }
298
299    /*
300     * Verify that this instance field ID is valid for this object.
301     *
302     * Assumes "jobj" has already been validated.
303     */
304    void checkInstanceFieldID(jobject jobj, jfieldID fieldID) {
305        ScopedJniThreadState ts(mEnv);
306
307        Object* obj = dvmDecodeIndirectRef(mEnv, jobj);
308        if (!dvmIsValidObject(obj)) {
309            LOGW("JNI ERROR: field operation on invalid reference (%p)", jobj);
310            dvmAbort();
311        }
312
313        /*
314         * Check this class and all of its superclasses for a matching field.
315         * Don't need to scan interfaces.
316         */
317        ClassObject* clazz = obj->clazz;
318        while (clazz != NULL) {
319            if ((InstField*) fieldID >= clazz->ifields &&
320                    (InstField*) fieldID < clazz->ifields + clazz->ifieldCount) {
321                return;
322            }
323
324            clazz = clazz->super;
325        }
326
327        LOGW("JNI WARNING: instance fieldID %p not valid for class %s",
328                fieldID, obj->clazz->descriptor);
329        showLocation();
330        abortMaybe();
331    }
332
333    /*
334     * Verify that the pointer value is non-NULL.
335     */
336    void checkNonNull(const void* ptr) {
337        if (ptr == NULL) {
338            LOGW("JNI WARNING: invalid null pointer (%s)", mFunctionName);
339            abortMaybe();
340        }
341    }
342
343    /*
344     * Verify that the method's return type matches the type of call.
345     * 'expectedType' will be "L" for all objects, including arrays.
346     */
347    void checkSig(jmethodID methodID, const char* expectedType, bool isStatic) {
348        const Method* method = (const Method*) methodID;
349        bool printWarn = false;
350
351        if (*expectedType != method->shorty[0]) {
352            LOGW("JNI WARNING: expected return type '%s'", expectedType);
353            printWarn = true;
354        } else if (isStatic && !dvmIsStaticMethod(method)) {
355            if (isStatic) {
356                LOGW("JNI WARNING: calling non-static method with static call");
357            } else {
358                LOGW("JNI WARNING: calling static method with non-static call");
359            }
360            printWarn = true;
361        }
362
363        if (printWarn) {
364            char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
365            LOGW("             calling %s.%s %s", method->clazz->descriptor, method->name, desc);
366            free(desc);
367            showLocation();
368            abortMaybe();
369        }
370    }
371
372    /*
373     * Verify that this static field ID is valid for this class.
374     *
375     * Assumes "jclazz" has already been validated.
376     */
377    void checkStaticFieldID(jclass jclazz, jfieldID fieldID) {
378        ScopedJniThreadState ts(mEnv);
379        ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(mEnv, jclazz);
380        StaticField* base = &clazz->sfields[0];
381        int fieldCount = clazz->sfieldCount;
382        if ((StaticField*) fieldID < base || (StaticField*) fieldID >= base + fieldCount) {
383            LOGW("JNI WARNING: static fieldID %p not valid for class %s",
384                    fieldID, clazz->descriptor);
385            LOGW("             base=%p count=%d", base, fieldCount);
386            showLocation();
387            abortMaybe();
388        }
389    }
390
391    /*
392     * Verify that "methodID" is appropriate for "clazz".
393     *
394     * A mismatch isn't dangerous, because the jmethodID defines the class.  In
395     * fact, jclazz is unused in the implementation.  It's best if we don't
396     * allow bad code in the system though.
397     *
398     * Instances of "jclazz" must be instances of the method's declaring class.
399     */
400    void checkStaticMethod(jclass jclazz, jmethodID methodID) {
401        ScopedJniThreadState ts(mEnv);
402
403        ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(mEnv, jclazz);
404        const Method* method = (const Method*) methodID;
405
406        if (!dvmInstanceof(clazz, method->clazz)) {
407            LOGW("JNI WARNING: can't call static %s.%s on class %s",
408                    method->clazz->descriptor, method->name, clazz->descriptor);
409            showLocation();
410            // no abort?
411        }
412    }
413
414    /*
415     * Verify that "methodID" is appropriate for "jobj".
416     *
417     * Make sure the object is an instance of the method's declaring class.
418     * (Note the methodID might point to a declaration in an interface; this
419     * will be handled automatically by the instanceof check.)
420     */
421    void checkVirtualMethod(jobject jobj, jmethodID methodID) {
422        ScopedJniThreadState ts(mEnv);
423
424        Object* obj = dvmDecodeIndirectRef(mEnv, jobj);
425        const Method* method = (const Method*) methodID;
426
427        if (!dvmInstanceof(obj->clazz, method->clazz)) {
428            LOGW("JNI WARNING: can't call %s.%s on instance of %s",
429                    method->clazz->descriptor, method->name, obj->clazz->descriptor);
430            showLocation();
431            abortMaybe();
432        }
433    }
434
435    /**
436     * The format string is a sequence of the following characters,
437     * and must be followed by arguments of the corresponding types
438     * in the same order.
439     *
440     * Java primitive types:
441     * B - jbyte
442     * C - jchar
443     * D - jdouble
444     * F - jfloat
445     * I - jint
446     * J - jlong
447     * S - jshort
448     * Z - jboolean (shown as true and false)
449     * V - void
450     *
451     * Java reference types:
452     * L - jobject
453     * a - jarray
454     * c - jclass
455     * s - jstring
456     *
457     * JNI types:
458     * b - jboolean (shown as JNI_TRUE and JNI_FALSE)
459     * f - jfieldID
460     * m - jmethodID
461     * p - void*
462     * r - jint (for release mode arguments)
463     * u - const char* (modified UTF-8)
464     * z - jsize (for lengths; use i if negative values are okay)
465     * v - JavaVM*
466     * E - JNIEnv*
467     * . - no argument; just print "..." (used for varargs JNI calls)
468     *
469     * Use the kFlag_NullableUtf flag where 'u' field(s) are nullable.
470     */
471    void check(bool entry, const char* fmt0, ...) {
472        va_list ap;
473
474        bool shouldTrace = false;
475        const Method* method = NULL;
476        if ((gDvm.jniTrace || gDvmJni.logThirdPartyJni) && mHasMethod) {
477            // We need to guard some of the invocation interface's calls: a bad caller might
478            // use DetachCurrentThread or GetEnv on a thread that's not yet attached.
479            if ((mFlags & kFlag_Invocation) == 0 || dvmThreadSelf() != NULL) {
480                method = dvmGetCurrentJNIMethod();
481            }
482        }
483        if (method != NULL) {
484            // If both "-Xcheck:jni" and "-Xjnitrace:" are enabled, we print trace messages
485            // when a native method that matches the Xjnitrace argument calls a JNI function
486            // such as NewByteArray.
487            if (gDvm.jniTrace && strstr(method->clazz->descriptor, gDvm.jniTrace) != NULL) {
488                shouldTrace = true;
489            }
490            // If -Xjniopts:logThirdPartyJni is on, we want to log any JNI function calls
491            // made by a third-party native method.
492            if (gDvmJni.logThirdPartyJni) {
493                shouldTrace |= method->shouldTrace;
494            }
495        }
496
497        if (shouldTrace) {
498            va_start(ap, fmt0);
499            std::string msg;
500            for (const char* fmt = fmt0; *fmt;) {
501                char ch = *fmt++;
502                if (ch == 'B') { // jbyte
503                    jbyte b = va_arg(ap, int);
504                    if (b >= 0 && b < 10) {
505                        StringAppendF(&msg, "%d", b);
506                    } else {
507                        StringAppendF(&msg, "%#x (%d)", b, b);
508                    }
509                } else if (ch == 'C') { // jchar
510                    jchar c = va_arg(ap, int);
511                    if (c < 0x7f && c >= ' ') {
512                        StringAppendF(&msg, "U+%x ('%c')", c, c);
513                    } else {
514                        StringAppendF(&msg, "U+%x", c);
515                    }
516                } else if (ch == 'F' || ch == 'D') { // jfloat, jdouble
517                    StringAppendF(&msg, "%g", va_arg(ap, double));
518                } else if (ch == 'I' || ch == 'S') { // jint, jshort
519                    StringAppendF(&msg, "%d", va_arg(ap, int));
520                } else if (ch == 'J') { // jlong
521                    StringAppendF(&msg, "%lld", va_arg(ap, jlong));
522                } else if (ch == 'Z') { // jboolean
523                    StringAppendF(&msg, "%s", va_arg(ap, int) ? "true" : "false");
524                } else if (ch == 'V') { // void
525                    msg += "void";
526                } else if (ch == 'v') { // JavaVM*
527                    JavaVM* vm = va_arg(ap, JavaVM*);
528                    StringAppendF(&msg, "(JavaVM*)%p", vm);
529                } else if (ch == 'E') { // JNIEnv*
530                    JNIEnv* env = va_arg(ap, JNIEnv*);
531                    StringAppendF(&msg, "(JNIEnv*)%p", env);
532                } else if (ch == 'L' || ch == 'a' || ch == 's') { // jobject, jarray, jstring
533                    // For logging purposes, these are identical.
534                    jobject o = va_arg(ap, jobject);
535                    if (o == NULL) {
536                        msg += "NULL";
537                    } else {
538                        StringAppendF(&msg, "%p", o);
539                    }
540                } else if (ch == 'b') { // jboolean (JNI-style)
541                    jboolean b = va_arg(ap, int);
542                    msg += (b ? "JNI_TRUE" : "JNI_FALSE");
543                } else if (ch == 'c') { // jclass
544                    jclass jc = va_arg(ap, jclass);
545                    Object* c = dvmDecodeIndirectRef(mEnv, jc);
546                    if (c == NULL) {
547                        msg += "NULL";
548                    } else if (c == kInvalidIndirectRefObject || !dvmIsValidObject(c)) {
549                        StringAppendF(&msg, "%p(INVALID)", jc);
550                    } else {
551                        std::string className(dvmHumanReadableType(c));
552                        StringAppendF(&msg, "%s", className.c_str());
553                        if (!entry) {
554                            StringAppendF(&msg, " (%p)", jc);
555                        }
556                    }
557                } else if (ch == 'f') { // jfieldID
558                    jfieldID fid = va_arg(ap, jfieldID);
559                    std::string name(dvmHumanReadableField((Field*) fid));
560                    StringAppendF(&msg, "%s", name.c_str());
561                    if (!entry) {
562                        StringAppendF(&msg, " (%p)", fid);
563                    }
564                } else if (ch == 'z') { // non-negative jsize
565                    // You might expect jsize to be size_t, but it's not; it's the same as jint.
566                    // We only treat this specially so we can do the non-negative check.
567                    // TODO: maybe this wasn't worth it?
568                    jint i = va_arg(ap, jint);
569                    StringAppendF(&msg, "%d", i);
570                } else if (ch == 'm') { // jmethodID
571                    jmethodID mid = va_arg(ap, jmethodID);
572                    std::string name(dvmHumanReadableMethod((Method*) mid, true));
573                    StringAppendF(&msg, "%s", name.c_str());
574                    if (!entry) {
575                        StringAppendF(&msg, " (%p)", mid);
576                    }
577                } else if (ch == 'p') { // void* ("pointer")
578                    void* p = va_arg(ap, void*);
579                    if (p == NULL) {
580                        msg += "NULL";
581                    } else {
582                        StringAppendF(&msg, "(void*) %p", p);
583                    }
584                } else if (ch == 'r') { // jint (release mode)
585                    jint releaseMode = va_arg(ap, jint);
586                    if (releaseMode == 0) {
587                        msg += "0";
588                    } else if (releaseMode == JNI_ABORT) {
589                        msg += "JNI_ABORT";
590                    } else if (releaseMode == JNI_COMMIT) {
591                        msg += "JNI_COMMIT";
592                    } else {
593                        StringAppendF(&msg, "invalid release mode %d", releaseMode);
594                    }
595                } else if (ch == 'u') { // const char* (modified UTF-8)
596                    const char* utf = va_arg(ap, const char*);
597                    if (utf == NULL) {
598                        msg += "NULL";
599                    } else {
600                        StringAppendF(&msg, "\"%s\"", utf);
601                    }
602                } else if (ch == '.') {
603                    msg += "...";
604                } else {
605                    LOGE("unknown trace format specifier %c", ch);
606                    dvmAbort();
607                }
608                if (*fmt) {
609                    StringAppendF(&msg, ", ");
610                }
611            }
612            va_end(ap);
613
614            if (entry) {
615                if (mHasMethod) {
616                    std::string methodName(dvmHumanReadableMethod(method, false));
617                    LOGI("JNI: %s -> %s(%s)", methodName.c_str(), mFunctionName, msg.c_str());
618                    mIndent = methodName.size() + 1;
619                } else {
620                    LOGI("JNI: -> %s(%s)", mFunctionName, msg.c_str());
621                    mIndent = 0;
622                }
623            } else {
624                LOGI("JNI: %*s<- %s returned %s", mIndent, "", mFunctionName, msg.c_str());
625            }
626        }
627
628        // We always do the thorough checks on entry, and never on exit...
629        if (entry) {
630            va_start(ap, fmt0);
631            for (const char* fmt = fmt0; *fmt; ++fmt) {
632                char ch = *fmt;
633                if (ch == 'a') {
634                    checkArray(va_arg(ap, jarray));
635                } else if (ch == 'c') {
636                    checkClass(va_arg(ap, jclass));
637                } else if (ch == 'L') {
638                    checkObject(va_arg(ap, jobject));
639                } else if (ch == 'r') {
640                    checkReleaseMode(va_arg(ap, jint));
641                } else if (ch == 's') {
642                    checkString(va_arg(ap, jstring));
643                } else if (ch == 'u') {
644                    if ((mFlags & kFlag_Release) != 0) {
645                        checkNonNull(va_arg(ap, const char*));
646                    } else {
647                        bool nullable = ((mFlags & kFlag_NullableUtf) != 0);
648                        checkUtfString(va_arg(ap, const char*), nullable);
649                    }
650                } else if (ch == 'z') {
651                    checkLengthPositive(va_arg(ap, jsize));
652                } else if (strchr("BCISZbfmpEv", ch) != NULL) {
653                    va_arg(ap, int); // Skip this argument.
654                } else if (ch == 'D' || ch == 'F') {
655                    va_arg(ap, double); // Skip this argument.
656                } else if (ch == 'J') {
657                    va_arg(ap, long); // Skip this argument.
658                } else if (ch == '.') {
659                } else {
660                    LOGE("unknown check format specifier %c", ch);
661                    dvmAbort();
662                }
663            }
664            va_end(ap);
665        }
666    }
667
668private:
669    JNIEnv* mEnv;
670    const char* mFunctionName;
671    int mFlags;
672    bool mHasMethod;
673    size_t mIndent;
674
675    void init(JNIEnv* env, int flags, const char* functionName, bool hasMethod) {
676        mEnv = env;
677        mFlags = flags;
678
679        // Use +6 to drop the leading "Check_"...
680        mFunctionName = functionName + 6;
681
682        // Set "hasMethod" to true if we have a valid thread with a method pointer.
683        // We won't have one before attaching a thread, after detaching a thread, or
684        // after destroying the VM.
685        mHasMethod = hasMethod;
686    }
687
688    /*
689     * Verify that "array" is non-NULL and points to an Array object.
690     *
691     * Since we're dealing with objects, switch to "running" mode.
692     */
693    void checkArray(jarray jarr) {
694        if (jarr == NULL) {
695            LOGW("JNI WARNING: received null array");
696            showLocation();
697            abortMaybe();
698            return;
699        }
700
701        ScopedJniThreadState ts(mEnv);
702        bool printWarn = false;
703
704        Object* obj = dvmDecodeIndirectRef(mEnv, jarr);
705
706        if (!dvmIsValidObject(obj)) {
707            LOGW("JNI WARNING: jarray is an invalid %s reference (%p)",
708            indirectRefKindName(jarr), jarr);
709            printWarn = true;
710        } else if (obj->clazz->descriptor[0] != '[') {
711            LOGW("JNI WARNING: jarray arg has wrong type (expected array, got %s)",
712            obj->clazz->descriptor);
713            printWarn = true;
714        }
715
716        if (printWarn) {
717            showLocation();
718            abortMaybe();
719        }
720    }
721
722    void checkClass(jclass c) {
723        checkInstance(c, gDvm.classJavaLangClass, "jclass");
724    }
725
726    void checkLengthPositive(jsize length) {
727        if (length < 0) {
728            LOGW("JNI WARNING: negative jsize (%s)", mFunctionName);
729            abortMaybe();
730        }
731    }
732
733    /*
734     * Verify that "jobj" is a valid object, and that it's an object that JNI
735     * is allowed to know about.  We allow NULL references.
736     *
737     * Switches to "running" mode before performing checks.
738     */
739    void checkObject(jobject jobj) {
740        if (jobj == NULL) {
741            return;
742        }
743
744        ScopedJniThreadState ts(mEnv);
745
746        bool printWarn = false;
747        if (dvmGetJNIRefType(mEnv, jobj) == JNIInvalidRefType) {
748            LOGW("JNI WARNING: %p is not a valid JNI reference", jobj);
749            printWarn = true;
750        } else {
751            Object* obj = dvmDecodeIndirectRef(mEnv, jobj);
752
753            /*
754             * The decoded object will be NULL if this is a weak global ref
755             * with a cleared referent.
756             */
757            if (obj == kInvalidIndirectRefObject || (obj != NULL && !dvmIsValidObject(obj))) {
758                LOGW("JNI WARNING: native code passing in bad object %p %p", jobj, obj);
759                printWarn = true;
760            }
761        }
762
763        if (printWarn) {
764            showLocation();
765            abortMaybe();
766        }
767    }
768
769    /*
770     * Verify that the "mode" argument passed to a primitive array Release
771     * function is one of the valid values.
772     */
773    void checkReleaseMode(jint mode) {
774        if (mode != 0 && mode != JNI_COMMIT && mode != JNI_ABORT) {
775            LOGW("JNI WARNING: bad value for mode (%d) (%s)", mode, mFunctionName);
776            abortMaybe();
777        }
778    }
779
780    void checkString(jstring s) {
781        checkInstance(s, gDvm.classJavaLangString, "jstring");
782    }
783
784    void checkThread(int flags) {
785        // Get the *correct* JNIEnv by going through our TLS pointer.
786        JNIEnvExt* threadEnv = dvmGetJNIEnvForThread();
787
788        /*
789         * Verify that the current thread is (a) attached and (b) associated with
790         * this particular instance of JNIEnv.
791         */
792        bool printWarn = false;
793        if (threadEnv == NULL) {
794            LOGE("JNI ERROR: non-VM thread making JNI calls");
795            // don't set printWarn -- it'll try to call showLocation()
796            dvmAbort();
797        } else if ((JNIEnvExt*) mEnv != threadEnv) {
798            if (dvmThreadSelf()->threadId != threadEnv->envThreadId) {
799                LOGE("JNI: threadEnv != thread->env?");
800                dvmAbort();
801            }
802
803            LOGW("JNI WARNING: threadid=%d using env from threadid=%d",
804                    threadEnv->envThreadId, ((JNIEnvExt*) mEnv)->envThreadId);
805            printWarn = true;
806
807            /* this is a bad idea -- need to throw as we exit, or abort func */
808            //dvmThrowRuntimeException("invalid use of JNI env ptr");
809        } else if (((JNIEnvExt*) mEnv)->self != dvmThreadSelf()) {
810            /* correct JNIEnv*; make sure the "self" pointer is correct */
811            LOGE("JNI ERROR: env->self != thread-self (%p vs. %p)",
812                    ((JNIEnvExt*) mEnv)->self, dvmThreadSelf());
813            dvmAbort();
814        }
815
816        /*
817         * Verify that, if this thread previously made a critical "get" call, we
818         * do the corresponding "release" call before we try anything else.
819         */
820        switch (flags & kFlag_CritMask) {
821        case kFlag_CritOkay:    // okay to call this method
822            break;
823        case kFlag_CritBad:     // not okay to call
824            if (threadEnv->critical) {
825                LOGW("JNI WARNING: threadid=%d using JNI after critical get",
826                        threadEnv->envThreadId);
827                printWarn = true;
828            }
829            break;
830        case kFlag_CritGet:     // this is a "get" call
831            /* don't check here; we allow nested gets */
832            threadEnv->critical++;
833            break;
834        case kFlag_CritRelease: // this is a "release" call
835            threadEnv->critical--;
836            if (threadEnv->critical < 0) {
837                LOGW("JNI WARNING: threadid=%d called too many crit releases",
838                        threadEnv->envThreadId);
839                printWarn = true;
840            }
841            break;
842        default:
843            assert(false);
844        }
845
846        /*
847         * Verify that, if an exception has been raised, the native code doesn't
848         * make any JNI calls other than the Exception* methods.
849         */
850        bool printException = false;
851        if ((flags & kFlag_ExcepOkay) == 0 && dvmCheckException(dvmThreadSelf())) {
852            LOGW("JNI WARNING: JNI method called with exception pending");
853            printWarn = true;
854            printException = true;
855        }
856
857        if (printWarn) {
858            showLocation();
859        }
860        if (printException) {
861            LOGW("Pending exception is:");
862            dvmLogExceptionStackTrace();
863        }
864        if (printWarn) {
865            abortMaybe();
866        }
867    }
868
869    /*
870     * Verify that "bytes" points to valid "modified UTF-8" data.
871     */
872    void checkUtfString(const char* bytes, bool nullable) {
873        if (bytes == NULL) {
874            if (!nullable) {
875                LOGW("JNI WARNING: non-nullable const char* was NULL");
876                showLocation();
877                abortMaybe();
878            }
879            return;
880        }
881
882        const char* errorKind = NULL;
883        u1 utf8 = checkUtfBytes(bytes, &errorKind);
884        if (errorKind != NULL) {
885            LOGW("JNI WARNING: input is not valid UTF-8: illegal %s byte %#x", errorKind, utf8);
886            LOGW("             string: '%s'", bytes);
887            showLocation();
888            abortMaybe();
889        }
890    }
891
892    /*
893     * Verify that "jobj" is a valid non-NULL object reference, and points to
894     * an instance of expectedClass.
895     *
896     * Because we're looking at an object on the GC heap, we have to switch
897     * to "running" mode before doing the checks.
898     */
899    void checkInstance(jobject jobj, ClassObject* expectedClass, const char* argName) {
900        if (jobj == NULL) {
901            LOGW("JNI WARNING: received null %s", argName);
902            showLocation();
903            abortMaybe();
904            return;
905        }
906
907        ScopedJniThreadState ts(mEnv);
908        bool printWarn = false;
909
910        Object* obj = dvmDecodeIndirectRef(mEnv, jobj);
911
912        if (!dvmIsValidObject(obj)) {
913            LOGW("JNI WARNING: %s is an invalid %s reference (%p)",
914                    argName, indirectRefKindName(jobj), jobj);
915            printWarn = true;
916        } else if (obj->clazz != expectedClass) {
917            LOGW("JNI WARNING: %s arg has wrong type (expected %s, got %s)",
918                    argName, expectedClass->descriptor, obj->clazz->descriptor);
919            printWarn = true;
920        }
921
922        if (printWarn) {
923            showLocation();
924            abortMaybe();
925        }
926    }
927
928    static u1 checkUtfBytes(const char* bytes, const char** errorKind) {
929        while (*bytes != '\0') {
930            u1 utf8 = *(bytes++);
931            // Switch on the high four bits.
932            switch (utf8 >> 4) {
933            case 0x00:
934            case 0x01:
935            case 0x02:
936            case 0x03:
937            case 0x04:
938            case 0x05:
939            case 0x06:
940            case 0x07:
941                // Bit pattern 0xxx. No need for any extra bytes.
942                break;
943            case 0x08:
944            case 0x09:
945            case 0x0a:
946            case 0x0b:
947            case 0x0f:
948                /*
949                 * Bit pattern 10xx or 1111, which are illegal start bytes.
950                 * Note: 1111 is valid for normal UTF-8, but not the
951                 * modified UTF-8 used here.
952                 */
953                *errorKind = "start";
954                return utf8;
955            case 0x0e:
956                // Bit pattern 1110, so there are two additional bytes.
957                utf8 = *(bytes++);
958                if ((utf8 & 0xc0) != 0x80) {
959                    *errorKind = "continuation";
960                    return utf8;
961                }
962                // Fall through to take care of the final byte.
963            case 0x0c:
964            case 0x0d:
965                // Bit pattern 110x, so there is one additional byte.
966                utf8 = *(bytes++);
967                if ((utf8 & 0xc0) != 0x80) {
968                    *errorKind = "continuation";
969                    return utf8;
970                }
971                break;
972            }
973        }
974        return 0;
975    }
976
977    /**
978     * Returns a human-readable name for the given primitive type.
979     */
980    static const char* primitiveTypeToName(PrimitiveType primType) {
981        switch (primType) {
982        case PRIM_VOID:    return "void";
983        case PRIM_BOOLEAN: return "boolean";
984        case PRIM_BYTE:    return "byte";
985        case PRIM_SHORT:   return "short";
986        case PRIM_CHAR:    return "char";
987        case PRIM_INT:     return "int";
988        case PRIM_LONG:    return "long";
989        case PRIM_FLOAT:   return "float";
990        case PRIM_DOUBLE:  return "double";
991        case PRIM_NOT:     return "Object/array";
992        default:           return "???";
993        }
994    }
995
996    void showLocation() {
997        const Method* method = dvmGetCurrentJNIMethod();
998        char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
999        LOGW("             in %s.%s:%s (%s)", method->clazz->descriptor, method->name, desc, mFunctionName);
1000        free(desc);
1001    }
1002
1003    // Disallow copy and assignment.
1004    ScopedCheck(const ScopedCheck&);
1005    void operator=(const ScopedCheck&);
1006};
1007
1008/*
1009 * ===========================================================================
1010 *      Guarded arrays
1011 * ===========================================================================
1012 */
1013
1014#define kGuardLen       512         /* must be multiple of 2 */
1015#define kGuardPattern   0xd5e3      /* uncommon values; d5e3d5e3 invalid addr */
1016#define kGuardMagic     0xffd5aa96
1017
1018/* this gets tucked in at the start of the buffer; struct size must be even */
1019struct GuardedCopy {
1020    u4          magic;
1021    uLong       adler;
1022    size_t      originalLen;
1023    const void* originalPtr;
1024
1025    /* find the GuardedCopy given the pointer into the "live" data */
1026    static inline const GuardedCopy* fromData(const void* dataBuf) {
1027        return reinterpret_cast<const GuardedCopy*>(actualBuffer(dataBuf));
1028    }
1029
1030    /*
1031     * Create an over-sized buffer to hold the contents of "buf".  Copy it in,
1032     * filling in the area around it with guard data.
1033     *
1034     * We use a 16-bit pattern to make a rogue memset less likely to elude us.
1035     */
1036    static void* create(const void* buf, size_t len, bool modOkay) {
1037        size_t newLen = actualLength(len);
1038        u1* newBuf = debugAlloc(newLen);
1039
1040        /* fill it in with a pattern */
1041        u2* pat = (u2*) newBuf;
1042        for (size_t i = 0; i < newLen / 2; i++) {
1043            *pat++ = kGuardPattern;
1044        }
1045
1046        /* copy the data in; note "len" could be zero */
1047        memcpy(newBuf + kGuardLen / 2, buf, len);
1048
1049        /* if modification is not expected, grab a checksum */
1050        uLong adler = 0;
1051        if (!modOkay) {
1052            adler = adler32(0L, Z_NULL, 0);
1053            adler = adler32(adler, (const Bytef*)buf, len);
1054            *(uLong*)newBuf = adler;
1055        }
1056
1057        GuardedCopy* pExtra = reinterpret_cast<GuardedCopy*>(newBuf);
1058        pExtra->magic = kGuardMagic;
1059        pExtra->adler = adler;
1060        pExtra->originalPtr = buf;
1061        pExtra->originalLen = len;
1062
1063        return newBuf + kGuardLen / 2;
1064    }
1065
1066    /*
1067     * Free up the guard buffer, scrub it, and return the original pointer.
1068     */
1069    static void* destroy(void* dataBuf) {
1070        const GuardedCopy* pExtra = GuardedCopy::fromData(dataBuf);
1071        void* originalPtr = (void*) pExtra->originalPtr;
1072        size_t len = pExtra->originalLen;
1073        debugFree(dataBuf, len);
1074        return originalPtr;
1075    }
1076
1077    /*
1078     * Verify the guard area and, if "modOkay" is false, that the data itself
1079     * has not been altered.
1080     *
1081     * The caller has already checked that "dataBuf" is non-NULL.
1082     */
1083    static bool check(const void* dataBuf, bool modOkay) {
1084        static const u4 kMagicCmp = kGuardMagic;
1085        const u1* fullBuf = actualBuffer(dataBuf);
1086        const GuardedCopy* pExtra = GuardedCopy::fromData(dataBuf);
1087
1088        /*
1089         * Before we do anything with "pExtra", check the magic number.  We
1090         * do the check with memcmp rather than "==" in case the pointer is
1091         * unaligned.  If it points to completely bogus memory we're going
1092         * to crash, but there's no easy way around that.
1093         */
1094        if (memcmp(&pExtra->magic, &kMagicCmp, 4) != 0) {
1095            u1 buf[4];
1096            memcpy(buf, &pExtra->magic, 4);
1097            LOGE("JNI: guard magic does not match (found 0x%02x%02x%02x%02x) -- incorrect data pointer %p?",
1098                    buf[3], buf[2], buf[1], buf[0], dataBuf); /* assume little endian */
1099            return false;
1100        }
1101
1102        size_t len = pExtra->originalLen;
1103
1104        /* check bottom half of guard; skip over optional checksum storage */
1105        const u2* pat = (u2*) fullBuf;
1106        for (size_t i = sizeof(GuardedCopy) / 2; i < (kGuardLen / 2 - sizeof(GuardedCopy)) / 2; i++) {
1107            if (pat[i] != kGuardPattern) {
1108                LOGE("JNI: guard pattern(1) disturbed at %p + %d", fullBuf, i*2);
1109                return false;
1110            }
1111        }
1112
1113        int offset = kGuardLen / 2 + len;
1114        if (offset & 0x01) {
1115            /* odd byte; expected value depends on endian-ness of host */
1116            const u2 patSample = kGuardPattern;
1117            if (fullBuf[offset] != ((const u1*) &patSample)[1]) {
1118                LOGE("JNI: guard pattern disturbed in odd byte after %p (+%d) 0x%02x 0x%02x",
1119                        fullBuf, offset, fullBuf[offset], ((const u1*) &patSample)[1]);
1120                return false;
1121            }
1122            offset++;
1123        }
1124
1125        /* check top half of guard */
1126        pat = (u2*) (fullBuf + offset);
1127        for (size_t i = 0; i < kGuardLen / 4; i++) {
1128            if (pat[i] != kGuardPattern) {
1129                LOGE("JNI: guard pattern(2) disturbed at %p + %d", fullBuf, offset + i*2);
1130                return false;
1131            }
1132        }
1133
1134        /*
1135         * If modification is not expected, verify checksum.  Strictly speaking
1136         * this is wrong: if we told the client that we made a copy, there's no
1137         * reason they can't alter the buffer.
1138         */
1139        if (!modOkay) {
1140            uLong adler = adler32(0L, Z_NULL, 0);
1141            adler = adler32(adler, (const Bytef*)dataBuf, len);
1142            if (pExtra->adler != adler) {
1143                LOGE("JNI: buffer modified (0x%08lx vs 0x%08lx) at addr %p",
1144                        pExtra->adler, adler, dataBuf);
1145                return false;
1146            }
1147        }
1148
1149        return true;
1150    }
1151
1152private:
1153    static u1* debugAlloc(size_t len) {
1154        void* result = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
1155        if (result == MAP_FAILED) {
1156            LOGE("GuardedCopy::create mmap(%d) failed: %s", len, strerror(errno));
1157            dvmAbort();
1158        }
1159        return reinterpret_cast<u1*>(result);
1160    }
1161
1162    static void debugFree(void* dataBuf, size_t len) {
1163        u1* fullBuf = actualBuffer(dataBuf);
1164        size_t totalByteCount = actualLength(len);
1165        // TODO: we could mprotect instead, and keep the allocation around for a while.
1166        // This would be even more expensive, but it might catch more errors.
1167        // if (mprotect(fullBuf, totalByteCount, PROT_NONE) != 0) {
1168        //     LOGW("mprotect(PROT_NONE) failed: %s", strerror(errno));
1169        // }
1170        if (munmap(fullBuf, totalByteCount) != 0) {
1171            LOGW("munmap failed: %s", strerror(errno));
1172            dvmAbort();
1173        }
1174    }
1175
1176    static const u1* actualBuffer(const void* dataBuf) {
1177        return reinterpret_cast<const u1*>(dataBuf) - kGuardLen / 2;
1178    }
1179
1180    static u1* actualBuffer(void* dataBuf) {
1181        return reinterpret_cast<u1*>(dataBuf) - kGuardLen / 2;
1182    }
1183
1184    // Underlying length of a user allocation of 'length' bytes.
1185    static size_t actualLength(size_t length) {
1186        return (length + kGuardLen + 1) & ~0x01;
1187    }
1188};
1189
1190/*
1191 * Return the width, in bytes, of a primitive type.
1192 */
1193static int dvmPrimitiveTypeWidth(PrimitiveType primType) {
1194    switch (primType) {
1195        case PRIM_BOOLEAN: return 1;
1196        case PRIM_BYTE:    return 1;
1197        case PRIM_SHORT:   return 2;
1198        case PRIM_CHAR:    return 2;
1199        case PRIM_INT:     return 4;
1200        case PRIM_LONG:    return 8;
1201        case PRIM_FLOAT:   return 4;
1202        case PRIM_DOUBLE:  return 8;
1203        case PRIM_VOID:
1204        default: {
1205            assert(false);
1206            return -1;
1207        }
1208    }
1209}
1210
1211/*
1212 * Create a guarded copy of a primitive array.  Modifications to the copied
1213 * data are allowed.  Returns a pointer to the copied data.
1214 */
1215static void* createGuardedPACopy(JNIEnv* env, const jarray jarr, jboolean* isCopy) {
1216    ScopedJniThreadState ts(env);
1217
1218    ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
1219    PrimitiveType primType = arrObj->clazz->elementClass->primitiveType;
1220    int len = arrObj->length * dvmPrimitiveTypeWidth(primType);
1221    void* result = GuardedCopy::create(arrObj->contents, len, true);
1222    if (isCopy != NULL) {
1223        *isCopy = JNI_TRUE;
1224    }
1225    return result;
1226}
1227
1228/*
1229 * Perform the array "release" operation, which may or may not copy data
1230 * back into the VM, and may or may not release the underlying storage.
1231 */
1232static void* releaseGuardedPACopy(JNIEnv* env, jarray jarr, void* dataBuf, int mode) {
1233    ScopedJniThreadState ts(env);
1234    ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
1235
1236    if (!GuardedCopy::check(dataBuf, true)) {
1237        LOGE("JNI: failed guarded copy check in releaseGuardedPACopy");
1238        abortMaybe();
1239        return NULL;
1240    }
1241
1242    if (mode != JNI_ABORT) {
1243        size_t len = GuardedCopy::fromData(dataBuf)->originalLen;
1244        memcpy(arrObj->contents, dataBuf, len);
1245    }
1246
1247    u1* result = NULL;
1248    if (mode != JNI_COMMIT) {
1249        result = (u1*) GuardedCopy::destroy(dataBuf);
1250    } else {
1251        result = (u1*) (void*) GuardedCopy::fromData(dataBuf)->originalPtr;
1252    }
1253
1254    /* pointer is to the array contents; back up to the array object */
1255    result -= OFFSETOF_MEMBER(ArrayObject, contents);
1256    return result;
1257}
1258
1259
1260/*
1261 * ===========================================================================
1262 *      JNI functions
1263 * ===========================================================================
1264 */
1265
1266#define CHECK_JNI_ENTRY(flags, types, args...) \
1267    ScopedCheck sc(env, flags, __FUNCTION__); \
1268    sc.check(true, types, ##args)
1269
1270#define CHECK_JNI_EXIT(type, exp) ({ \
1271    typeof (exp) _rc = (exp); \
1272    sc.check(false, type, _rc); \
1273    _rc; })
1274#define CHECK_JNI_EXIT_VOID() \
1275    sc.check(false, "V")
1276
1277static jint Check_GetVersion(JNIEnv* env) {
1278    CHECK_JNI_ENTRY(kFlag_Default, "E", env);
1279    return CHECK_JNI_EXIT("I", baseEnv(env)->GetVersion(env));
1280}
1281
1282static jclass Check_DefineClass(JNIEnv* env, const char* name, jobject loader,
1283    const jbyte* buf, jsize bufLen)
1284{
1285    CHECK_JNI_ENTRY(kFlag_Default, "EuLpz", env, name, loader, buf, bufLen);
1286    sc.checkClassName(name);
1287    return CHECK_JNI_EXIT("c", baseEnv(env)->DefineClass(env, name, loader, buf, bufLen));
1288}
1289
1290static jclass Check_FindClass(JNIEnv* env, const char* name) {
1291    CHECK_JNI_ENTRY(kFlag_Default, "Eu", env, name);
1292    sc.checkClassName(name);
1293    return CHECK_JNI_EXIT("c", baseEnv(env)->FindClass(env, name));
1294}
1295
1296static jclass Check_GetSuperclass(JNIEnv* env, jclass clazz) {
1297    CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz);
1298    return CHECK_JNI_EXIT("c", baseEnv(env)->GetSuperclass(env, clazz));
1299}
1300
1301static jboolean Check_IsAssignableFrom(JNIEnv* env, jclass clazz1, jclass clazz2) {
1302    CHECK_JNI_ENTRY(kFlag_Default, "Ecc", env, clazz1, clazz2);
1303    return CHECK_JNI_EXIT("b", baseEnv(env)->IsAssignableFrom(env, clazz1, clazz2));
1304}
1305
1306static jmethodID Check_FromReflectedMethod(JNIEnv* env, jobject method) {
1307    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, method);
1308    // TODO: check that 'field' is a java.lang.reflect.Method.
1309    return CHECK_JNI_EXIT("m", baseEnv(env)->FromReflectedMethod(env, method));
1310}
1311
1312static jfieldID Check_FromReflectedField(JNIEnv* env, jobject field) {
1313    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, field);
1314    // TODO: check that 'field' is a java.lang.reflect.Field.
1315    return CHECK_JNI_EXIT("f", baseEnv(env)->FromReflectedField(env, field));
1316}
1317
1318static jobject Check_ToReflectedMethod(JNIEnv* env, jclass cls,
1319        jmethodID methodID, jboolean isStatic)
1320{
1321    CHECK_JNI_ENTRY(kFlag_Default, "Ecmb", env, cls, methodID, isStatic);
1322    return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedMethod(env, cls, methodID, isStatic));
1323}
1324
1325static jobject Check_ToReflectedField(JNIEnv* env, jclass cls,
1326        jfieldID fieldID, jboolean isStatic)
1327{
1328    CHECK_JNI_ENTRY(kFlag_Default, "Ecfb", env, cls, fieldID, isStatic);
1329    return CHECK_JNI_EXIT("L", baseEnv(env)->ToReflectedField(env, cls, fieldID, isStatic));
1330}
1331
1332static jint Check_Throw(JNIEnv* env, jthrowable obj) {
1333    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1334    // TODO: check that 'obj' is a java.lang.Throwable.
1335    return CHECK_JNI_EXIT("I", baseEnv(env)->Throw(env, obj));
1336}
1337
1338static jint Check_ThrowNew(JNIEnv* env, jclass clazz, const char* message) {
1339    CHECK_JNI_ENTRY(kFlag_NullableUtf, "Ecu", env, clazz, message);
1340    return CHECK_JNI_EXIT("I", baseEnv(env)->ThrowNew(env, clazz, message));
1341}
1342
1343static jthrowable Check_ExceptionOccurred(JNIEnv* env) {
1344    CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
1345    return CHECK_JNI_EXIT("L", baseEnv(env)->ExceptionOccurred(env));
1346}
1347
1348static void Check_ExceptionDescribe(JNIEnv* env) {
1349    CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
1350    baseEnv(env)->ExceptionDescribe(env);
1351    CHECK_JNI_EXIT_VOID();
1352}
1353
1354static void Check_ExceptionClear(JNIEnv* env) {
1355    CHECK_JNI_ENTRY(kFlag_ExcepOkay, "E", env);
1356    baseEnv(env)->ExceptionClear(env);
1357    CHECK_JNI_EXIT_VOID();
1358}
1359
1360static void Check_FatalError(JNIEnv* env, const char* msg) {
1361    CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, msg);
1362    baseEnv(env)->FatalError(env, msg);
1363    CHECK_JNI_EXIT_VOID();
1364}
1365
1366static jint Check_PushLocalFrame(JNIEnv* env, jint capacity) {
1367    CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EI", env, capacity);
1368    return CHECK_JNI_EXIT("I", baseEnv(env)->PushLocalFrame(env, capacity));
1369}
1370
1371static jobject Check_PopLocalFrame(JNIEnv* env, jobject res) {
1372    CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, res);
1373    return CHECK_JNI_EXIT("L", baseEnv(env)->PopLocalFrame(env, res));
1374}
1375
1376static jobject Check_NewGlobalRef(JNIEnv* env, jobject obj) {
1377    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1378    return CHECK_JNI_EXIT("L", baseEnv(env)->NewGlobalRef(env, obj));
1379}
1380
1381static void Check_DeleteGlobalRef(JNIEnv* env, jobject globalRef) {
1382    CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, globalRef);
1383    if (globalRef != NULL && dvmGetJNIRefType(env, globalRef) != JNIGlobalRefType) {
1384        LOGW("JNI WARNING: DeleteGlobalRef on non-global %p (type=%d)",
1385            globalRef, dvmGetJNIRefType(env, globalRef));
1386        abortMaybe();
1387    } else {
1388        baseEnv(env)->DeleteGlobalRef(env, globalRef);
1389        CHECK_JNI_EXIT_VOID();
1390    }
1391}
1392
1393static jobject Check_NewLocalRef(JNIEnv* env, jobject ref) {
1394    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, ref);
1395    return CHECK_JNI_EXIT("L", baseEnv(env)->NewLocalRef(env, ref));
1396}
1397
1398static void Check_DeleteLocalRef(JNIEnv* env, jobject localRef) {
1399    CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, localRef);
1400    if (localRef != NULL && dvmGetJNIRefType(env, localRef) != JNILocalRefType) {
1401        LOGW("JNI WARNING: DeleteLocalRef on non-local %p (type=%d)",
1402            localRef, dvmGetJNIRefType(env, localRef));
1403        abortMaybe();
1404    } else {
1405        baseEnv(env)->DeleteLocalRef(env, localRef);
1406        CHECK_JNI_EXIT_VOID();
1407    }
1408}
1409
1410static jint Check_EnsureLocalCapacity(JNIEnv *env, jint capacity) {
1411    CHECK_JNI_ENTRY(kFlag_Default, "EI", env, capacity);
1412    return CHECK_JNI_EXIT("I", baseEnv(env)->EnsureLocalCapacity(env, capacity));
1413}
1414
1415static jboolean Check_IsSameObject(JNIEnv* env, jobject ref1, jobject ref2) {
1416    CHECK_JNI_ENTRY(kFlag_Default, "ELL", env, ref1, ref2);
1417    return CHECK_JNI_EXIT("b", baseEnv(env)->IsSameObject(env, ref1, ref2));
1418}
1419
1420static jobject Check_AllocObject(JNIEnv* env, jclass clazz) {
1421    CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz);
1422    return CHECK_JNI_EXIT("L", baseEnv(env)->AllocObject(env, clazz));
1423}
1424
1425static jobject Check_NewObject(JNIEnv* env, jclass clazz, jmethodID methodID, ...) {
1426    CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID);
1427    va_list args;
1428    va_start(args, methodID);
1429    jobject result = baseEnv(env)->NewObjectV(env, clazz, methodID, args);
1430    va_end(args);
1431    return CHECK_JNI_EXIT("L", result);
1432}
1433
1434static jobject Check_NewObjectV(JNIEnv* env, jclass clazz, jmethodID methodID, va_list args) {
1435    CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID);
1436    return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectV(env, clazz, methodID, args));
1437}
1438
1439static jobject Check_NewObjectA(JNIEnv* env, jclass clazz, jmethodID methodID, jvalue* args) {
1440    CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID);
1441    return CHECK_JNI_EXIT("L", baseEnv(env)->NewObjectA(env, clazz, methodID, args));
1442}
1443
1444static jclass Check_GetObjectClass(JNIEnv* env, jobject obj) {
1445    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1446    return CHECK_JNI_EXIT("c", baseEnv(env)->GetObjectClass(env, obj));
1447}
1448
1449static jboolean Check_IsInstanceOf(JNIEnv* env, jobject obj, jclass clazz) {
1450    CHECK_JNI_ENTRY(kFlag_Default, "ELc", env, obj, clazz);
1451    return CHECK_JNI_EXIT("b", baseEnv(env)->IsInstanceOf(env, obj, clazz));
1452}
1453
1454static jmethodID Check_GetMethodID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1455    CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1456    return CHECK_JNI_EXIT("m", baseEnv(env)->GetMethodID(env, clazz, name, sig));
1457}
1458
1459static jfieldID Check_GetFieldID(JNIEnv* env, jclass clazz, const char* name, const char* sig) {
1460    CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1461    return CHECK_JNI_EXIT("f", baseEnv(env)->GetFieldID(env, clazz, name, sig));
1462}
1463
1464static jmethodID Check_GetStaticMethodID(JNIEnv* env, jclass clazz,
1465        const char* name, const char* sig)
1466{
1467    CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1468    return CHECK_JNI_EXIT("m", baseEnv(env)->GetStaticMethodID(env, clazz, name, sig));
1469}
1470
1471static jfieldID Check_GetStaticFieldID(JNIEnv* env, jclass clazz,
1472        const char* name, const char* sig)
1473{
1474    CHECK_JNI_ENTRY(kFlag_Default, "Ecuu", env, clazz, name, sig);
1475    return CHECK_JNI_EXIT("f", baseEnv(env)->GetStaticFieldID(env, clazz, name, sig));
1476}
1477
1478#define FIELD_ACCESSORS(_ctype, _jname, _ftype, _type) \
1479    static _ctype Check_GetStatic##_jname##Field(JNIEnv* env, jclass clazz, jfieldID fieldID) { \
1480        CHECK_JNI_ENTRY(kFlag_Default, "Ecf", env, clazz, fieldID); \
1481        sc.checkStaticFieldID(clazz, fieldID); \
1482        return CHECK_JNI_EXIT(_type, baseEnv(env)->GetStatic##_jname##Field(env, clazz, fieldID)); \
1483    } \
1484    static _ctype Check_Get##_jname##Field(JNIEnv* env, jobject obj, jfieldID fieldID) { \
1485        CHECK_JNI_ENTRY(kFlag_Default, "ELf", env, obj, fieldID); \
1486        sc.checkInstanceFieldID(obj, fieldID); \
1487        return CHECK_JNI_EXIT(_type, baseEnv(env)->Get##_jname##Field(env, obj, fieldID)); \
1488    } \
1489    static void Check_SetStatic##_jname##Field(JNIEnv* env, jclass clazz, jfieldID fieldID, _ctype value) { \
1490        CHECK_JNI_ENTRY(kFlag_Default, "Ecf" _type, env, clazz, fieldID, value); \
1491        sc.checkStaticFieldID(clazz, fieldID); \
1492        /* "value" arg only used when type == ref */ \
1493        sc.checkFieldType((jobject)(u4)value, fieldID, _ftype, true); \
1494        baseEnv(env)->SetStatic##_jname##Field(env, clazz, fieldID, value); \
1495        CHECK_JNI_EXIT_VOID(); \
1496    } \
1497    static void Check_Set##_jname##Field(JNIEnv* env, jobject obj, jfieldID fieldID, _ctype value) { \
1498        CHECK_JNI_ENTRY(kFlag_Default, "ELf" _type, env, obj, fieldID, value); \
1499        sc.checkInstanceFieldID(obj, fieldID); \
1500        /* "value" arg only used when type == ref */ \
1501        sc.checkFieldType((jobject)(u4) value, fieldID, _ftype, false); \
1502        baseEnv(env)->Set##_jname##Field(env, obj, fieldID, value); \
1503        CHECK_JNI_EXIT_VOID(); \
1504    }
1505
1506FIELD_ACCESSORS(jobject, Object, PRIM_NOT, "L");
1507FIELD_ACCESSORS(jboolean, Boolean, PRIM_BOOLEAN, "Z");
1508FIELD_ACCESSORS(jbyte, Byte, PRIM_BYTE, "B");
1509FIELD_ACCESSORS(jchar, Char, PRIM_CHAR, "C");
1510FIELD_ACCESSORS(jshort, Short, PRIM_SHORT, "S");
1511FIELD_ACCESSORS(jint, Int, PRIM_INT, "I");
1512FIELD_ACCESSORS(jlong, Long, PRIM_LONG, "J");
1513FIELD_ACCESSORS(jfloat, Float, PRIM_FLOAT, "F");
1514FIELD_ACCESSORS(jdouble, Double, PRIM_DOUBLE, "D");
1515
1516#define CALL(_ctype, _jname, _retdecl, _retasgn, _retok, _retsig) \
1517    /* Virtual... */ \
1518    static _ctype Check_Call##_jname##Method(JNIEnv* env, jobject obj, \
1519        jmethodID methodID, ...) \
1520    { \
1521        CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, methodID); /* TODO: args! */ \
1522        sc.checkSig(methodID, _retsig, false); \
1523        sc.checkVirtualMethod(obj, methodID); \
1524        _retdecl; \
1525        va_list args; \
1526        va_start(args, methodID); \
1527        _retasgn baseEnv(env)->Call##_jname##MethodV(env, obj, methodID, args); \
1528        va_end(args); \
1529        _retok; \
1530    } \
1531    static _ctype Check_Call##_jname##MethodV(JNIEnv* env, jobject obj, \
1532        jmethodID methodID, va_list args) \
1533    { \
1534        CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, methodID); /* TODO: args! */ \
1535        sc.checkSig(methodID, _retsig, false); \
1536        sc.checkVirtualMethod(obj, methodID); \
1537        _retdecl; \
1538        _retasgn baseEnv(env)->Call##_jname##MethodV(env, obj, methodID, args); \
1539        _retok; \
1540    } \
1541    static _ctype Check_Call##_jname##MethodA(JNIEnv* env, jobject obj, \
1542        jmethodID methodID, jvalue* args) \
1543    { \
1544        CHECK_JNI_ENTRY(kFlag_Default, "ELm.", env, obj, methodID); /* TODO: args! */ \
1545        sc.checkSig(methodID, _retsig, false); \
1546        sc.checkVirtualMethod(obj, methodID); \
1547        _retdecl; \
1548        _retasgn baseEnv(env)->Call##_jname##MethodA(env, obj, methodID, args); \
1549        _retok; \
1550    } \
1551    /* Non-virtual... */ \
1552    static _ctype Check_CallNonvirtual##_jname##Method(JNIEnv* env, \
1553        jobject obj, jclass clazz, jmethodID methodID, ...) \
1554    { \
1555        CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, methodID); /* TODO: args! */ \
1556        sc.checkSig(methodID, _retsig, false); \
1557        sc.checkVirtualMethod(obj, methodID); \
1558        _retdecl; \
1559        va_list args; \
1560        va_start(args, methodID); \
1561        _retasgn baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, clazz, methodID, args); \
1562        va_end(args); \
1563        _retok; \
1564    } \
1565    static _ctype Check_CallNonvirtual##_jname##MethodV(JNIEnv* env, \
1566        jobject obj, jclass clazz, jmethodID methodID, va_list args) \
1567    { \
1568        CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, methodID); /* TODO: args! */ \
1569        sc.checkSig(methodID, _retsig, false); \
1570        sc.checkVirtualMethod(obj, methodID); \
1571        _retdecl; \
1572        _retasgn baseEnv(env)->CallNonvirtual##_jname##MethodV(env, obj, clazz, methodID, args); \
1573        _retok; \
1574    } \
1575    static _ctype Check_CallNonvirtual##_jname##MethodA(JNIEnv* env, \
1576        jobject obj, jclass clazz, jmethodID methodID, jvalue* args) \
1577    { \
1578        CHECK_JNI_ENTRY(kFlag_Default, "ELcm.", env, obj, clazz, methodID); /* TODO: args! */ \
1579        sc.checkSig(methodID, _retsig, false); \
1580        sc.checkVirtualMethod(obj, methodID); \
1581        _retdecl; \
1582        _retasgn baseEnv(env)->CallNonvirtual##_jname##MethodA(env, obj, clazz, methodID, args); \
1583        _retok; \
1584    } \
1585    /* Static... */ \
1586    static _ctype Check_CallStatic##_jname##Method(JNIEnv* env, \
1587        jclass clazz, jmethodID methodID, ...) \
1588    { \
1589        CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); /* TODO: args! */ \
1590        sc.checkSig(methodID, _retsig, true); \
1591        sc.checkStaticMethod(clazz, methodID); \
1592        _retdecl; \
1593        va_list args; \
1594        va_start(args, methodID); \
1595        _retasgn baseEnv(env)->CallStatic##_jname##MethodV(env, clazz, methodID, args); \
1596        va_end(args); \
1597        _retok; \
1598    } \
1599    static _ctype Check_CallStatic##_jname##MethodV(JNIEnv* env, \
1600        jclass clazz, jmethodID methodID, va_list args) \
1601    { \
1602        CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); /* TODO: args! */ \
1603        sc.checkSig(methodID, _retsig, true); \
1604        sc.checkStaticMethod(clazz, methodID); \
1605        _retdecl; \
1606        _retasgn baseEnv(env)->CallStatic##_jname##MethodV(env, clazz, methodID, args); \
1607        _retok; \
1608    } \
1609    static _ctype Check_CallStatic##_jname##MethodA(JNIEnv* env, \
1610        jclass clazz, jmethodID methodID, jvalue* args) \
1611    { \
1612        CHECK_JNI_ENTRY(kFlag_Default, "Ecm.", env, clazz, methodID); /* TODO: args! */ \
1613        sc.checkSig(methodID, _retsig, true); \
1614        sc.checkStaticMethod(clazz, methodID); \
1615        _retdecl; \
1616        _retasgn baseEnv(env)->CallStatic##_jname##MethodA(env, clazz, methodID, args); \
1617        _retok; \
1618    }
1619
1620#define NON_VOID_RETURN(_retsig, _ctype) return CHECK_JNI_EXIT(_retsig, (_ctype) result)
1621#define VOID_RETURN CHECK_JNI_EXIT_VOID()
1622
1623CALL(jobject, Object, Object* result, result=(Object*), NON_VOID_RETURN("L", jobject), "L");
1624CALL(jboolean, Boolean, jboolean result, result=, NON_VOID_RETURN("Z", jboolean), "Z");
1625CALL(jbyte, Byte, jbyte result, result=, NON_VOID_RETURN("B", jbyte), "B");
1626CALL(jchar, Char, jchar result, result=, NON_VOID_RETURN("C", jchar), "C");
1627CALL(jshort, Short, jshort result, result=, NON_VOID_RETURN("S", jshort), "S");
1628CALL(jint, Int, jint result, result=, NON_VOID_RETURN("I", jint), "I");
1629CALL(jlong, Long, jlong result, result=, NON_VOID_RETURN("J", jlong), "J");
1630CALL(jfloat, Float, jfloat result, result=, NON_VOID_RETURN("F", jfloat), "F");
1631CALL(jdouble, Double, jdouble result, result=, NON_VOID_RETURN("D", jdouble), "D");
1632CALL(void, Void, , , VOID_RETURN, "V");
1633
1634static jstring Check_NewString(JNIEnv* env, const jchar* unicodeChars, jsize len) {
1635    CHECK_JNI_ENTRY(kFlag_Default, "Epz", env, unicodeChars, len);
1636    return CHECK_JNI_EXIT("s", baseEnv(env)->NewString(env, unicodeChars, len));
1637}
1638
1639static jsize Check_GetStringLength(JNIEnv* env, jstring string) {
1640    CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string);
1641    return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringLength(env, string));
1642}
1643
1644static const jchar* Check_GetStringChars(JNIEnv* env, jstring string, jboolean* isCopy) {
1645    CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, string, isCopy);
1646    const jchar* result = baseEnv(env)->GetStringChars(env, string, isCopy);
1647    if (gDvmJni.forceCopy && result != NULL) {
1648        ScopedJniThreadState ts(env);
1649        StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, string);
1650        int byteCount = strObj->length() * 2;
1651        result = (const jchar*) GuardedCopy::create(result, byteCount, false);
1652        if (isCopy != NULL) {
1653            *isCopy = JNI_TRUE;
1654        }
1655    }
1656    return CHECK_JNI_EXIT("p", result);
1657}
1658
1659static void Check_ReleaseStringChars(JNIEnv* env, jstring string, const jchar* chars) {
1660    CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Esp", env, string, chars);
1661    sc.checkNonNull(chars);
1662    if (gDvmJni.forceCopy) {
1663        if (!GuardedCopy::check(chars, false)) {
1664            LOGE("JNI: failed guarded copy check in ReleaseStringChars");
1665            abortMaybe();
1666            return;
1667        }
1668        chars = (const jchar*) GuardedCopy::destroy((jchar*)chars);
1669    }
1670    baseEnv(env)->ReleaseStringChars(env, string, chars);
1671    CHECK_JNI_EXIT_VOID();
1672}
1673
1674static jstring Check_NewStringUTF(JNIEnv* env, const char* bytes) {
1675    CHECK_JNI_ENTRY(kFlag_NullableUtf, "Eu", env, bytes); // TODO: show pointer and truncate string.
1676    return CHECK_JNI_EXIT("s", baseEnv(env)->NewStringUTF(env, bytes));
1677}
1678
1679static jsize Check_GetStringUTFLength(JNIEnv* env, jstring string) {
1680    CHECK_JNI_ENTRY(kFlag_CritOkay, "Es", env, string);
1681    return CHECK_JNI_EXIT("I", baseEnv(env)->GetStringUTFLength(env, string));
1682}
1683
1684static const char* Check_GetStringUTFChars(JNIEnv* env, jstring string, jboolean* isCopy) {
1685    CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, string, isCopy);
1686    const char* result = baseEnv(env)->GetStringUTFChars(env, string, isCopy);
1687    if (gDvmJni.forceCopy && result != NULL) {
1688        result = (const char*) GuardedCopy::create(result, strlen(result) + 1, false);
1689        if (isCopy != NULL) {
1690            *isCopy = JNI_TRUE;
1691        }
1692    }
1693    return CHECK_JNI_EXIT("u", result); // TODO: show pointer and truncate string.
1694}
1695
1696static void Check_ReleaseStringUTFChars(JNIEnv* env, jstring string, const char* utf) {
1697    CHECK_JNI_ENTRY(kFlag_ExcepOkay | kFlag_Release, "Esu", env, string, utf); // TODO: show pointer and truncate string.
1698    if (gDvmJni.forceCopy) {
1699        if (!GuardedCopy::check(utf, false)) {
1700            LOGE("JNI: failed guarded copy check in ReleaseStringUTFChars");
1701            abortMaybe();
1702            return;
1703        }
1704        utf = (const char*) GuardedCopy::destroy((char*)utf);
1705    }
1706    baseEnv(env)->ReleaseStringUTFChars(env, string, utf);
1707    CHECK_JNI_EXIT_VOID();
1708}
1709
1710static jsize Check_GetArrayLength(JNIEnv* env, jarray array) {
1711    CHECK_JNI_ENTRY(kFlag_CritOkay, "Ea", env, array);
1712    return CHECK_JNI_EXIT("I", baseEnv(env)->GetArrayLength(env, array));
1713}
1714
1715static jobjectArray Check_NewObjectArray(JNIEnv* env, jsize length,
1716        jclass elementClass, jobject initialElement)
1717{
1718    CHECK_JNI_ENTRY(kFlag_Default, "EzcL", env, length, elementClass, initialElement);
1719    return CHECK_JNI_EXIT("a", baseEnv(env)->NewObjectArray(env, length, elementClass, initialElement));
1720}
1721
1722static jobject Check_GetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index) {
1723    CHECK_JNI_ENTRY(kFlag_Default, "EaI", env, array, index);
1724    return CHECK_JNI_EXIT("L", baseEnv(env)->GetObjectArrayElement(env, array, index));
1725}
1726
1727static void Check_SetObjectArrayElement(JNIEnv* env, jobjectArray array, jsize index, jobject value)
1728{
1729    CHECK_JNI_ENTRY(kFlag_Default, "EaIL", env, array, index, value);
1730    baseEnv(env)->SetObjectArrayElement(env, array, index, value);
1731    CHECK_JNI_EXIT_VOID();
1732}
1733
1734#define NEW_PRIMITIVE_ARRAY(_artype, _jname) \
1735    static _artype Check_New##_jname##Array(JNIEnv* env, jsize length) { \
1736        CHECK_JNI_ENTRY(kFlag_Default, "Ez", env, length); \
1737        return CHECK_JNI_EXIT("a", baseEnv(env)->New##_jname##Array(env, length)); \
1738    }
1739NEW_PRIMITIVE_ARRAY(jbooleanArray, Boolean);
1740NEW_PRIMITIVE_ARRAY(jbyteArray, Byte);
1741NEW_PRIMITIVE_ARRAY(jcharArray, Char);
1742NEW_PRIMITIVE_ARRAY(jshortArray, Short);
1743NEW_PRIMITIVE_ARRAY(jintArray, Int);
1744NEW_PRIMITIVE_ARRAY(jlongArray, Long);
1745NEW_PRIMITIVE_ARRAY(jfloatArray, Float);
1746NEW_PRIMITIVE_ARRAY(jdoubleArray, Double);
1747
1748
1749/*
1750 * Hack to allow forcecopy to work with jniGetNonMovableArrayElements.
1751 * The code deliberately uses an invalid sequence of operations, so we
1752 * need to pass it through unmodified.  Review that code before making
1753 * any changes here.
1754 */
1755#define kNoCopyMagic    0xd5aab57f
1756
1757#define GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
1758    static _ctype* Check_Get##_jname##ArrayElements(JNIEnv* env, \
1759        _ctype##Array array, jboolean* isCopy) \
1760    { \
1761        CHECK_JNI_ENTRY(kFlag_Default, "Eap", env, array, isCopy); \
1762        u4 noCopy = 0; \
1763        if (gDvmJni.forceCopy && isCopy != NULL) { \
1764            /* capture this before the base call tramples on it */ \
1765            noCopy = *(u4*) isCopy; \
1766        } \
1767        _ctype* result = baseEnv(env)->Get##_jname##ArrayElements(env, array, isCopy); \
1768        if (gDvmJni.forceCopy && result != NULL) { \
1769            if (noCopy == kNoCopyMagic) { \
1770                LOGV("FC: not copying %p %x", array, noCopy); \
1771            } else { \
1772                result = (_ctype*) createGuardedPACopy(env, array, isCopy); \
1773            } \
1774        } \
1775        return CHECK_JNI_EXIT("p", result); \
1776    }
1777
1778#define RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname) \
1779    static void Check_Release##_jname##ArrayElements(JNIEnv* env, \
1780        _ctype##Array array, _ctype* elems, jint mode) \
1781    { \
1782        CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "Eapr", env, array, elems, mode); \
1783        sc.checkNonNull(elems); \
1784        if (gDvmJni.forceCopy) { \
1785            if ((uintptr_t)elems == kNoCopyMagic) { \
1786                LOGV("FC: not freeing %p", array); \
1787                elems = NULL;   /* base JNI call doesn't currently need */ \
1788            } else { \
1789                elems = (_ctype*) releaseGuardedPACopy(env, array, elems, mode); \
1790            } \
1791        } \
1792        baseEnv(env)->Release##_jname##ArrayElements(env, array, elems, mode); \
1793        CHECK_JNI_EXIT_VOID(); \
1794    }
1795
1796#define GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
1797    static void Check_Get##_jname##ArrayRegion(JNIEnv* env, \
1798            _ctype##Array array, jsize start, jsize len, _ctype* buf) { \
1799        CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \
1800        baseEnv(env)->Get##_jname##ArrayRegion(env, array, start, len, buf); \
1801        CHECK_JNI_EXIT_VOID(); \
1802    }
1803
1804#define SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname) \
1805    static void Check_Set##_jname##ArrayRegion(JNIEnv* env, \
1806            _ctype##Array array, jsize start, jsize len, const _ctype* buf) { \
1807        CHECK_JNI_ENTRY(kFlag_Default, "EaIIp", env, array, start, len, buf); \
1808        baseEnv(env)->Set##_jname##ArrayRegion(env, array, start, len, buf); \
1809        CHECK_JNI_EXIT_VOID(); \
1810    }
1811
1812#define PRIMITIVE_ARRAY_FUNCTIONS(_ctype, _jname, _typechar) \
1813    GET_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
1814    RELEASE_PRIMITIVE_ARRAY_ELEMENTS(_ctype, _jname); \
1815    GET_PRIMITIVE_ARRAY_REGION(_ctype, _jname); \
1816    SET_PRIMITIVE_ARRAY_REGION(_ctype, _jname);
1817
1818/* TODO: verify primitive array type matches call type */
1819PRIMITIVE_ARRAY_FUNCTIONS(jboolean, Boolean, 'Z');
1820PRIMITIVE_ARRAY_FUNCTIONS(jbyte, Byte, 'B');
1821PRIMITIVE_ARRAY_FUNCTIONS(jchar, Char, 'C');
1822PRIMITIVE_ARRAY_FUNCTIONS(jshort, Short, 'S');
1823PRIMITIVE_ARRAY_FUNCTIONS(jint, Int, 'I');
1824PRIMITIVE_ARRAY_FUNCTIONS(jlong, Long, 'J');
1825PRIMITIVE_ARRAY_FUNCTIONS(jfloat, Float, 'F');
1826PRIMITIVE_ARRAY_FUNCTIONS(jdouble, Double, 'D');
1827
1828static jint Check_RegisterNatives(JNIEnv* env, jclass clazz, const JNINativeMethod* methods,
1829        jint nMethods)
1830{
1831    CHECK_JNI_ENTRY(kFlag_Default, "EcpI", env, clazz, methods, nMethods);
1832    return CHECK_JNI_EXIT("I", baseEnv(env)->RegisterNatives(env, clazz, methods, nMethods));
1833}
1834
1835static jint Check_UnregisterNatives(JNIEnv* env, jclass clazz) {
1836    CHECK_JNI_ENTRY(kFlag_Default, "Ec", env, clazz);
1837    return CHECK_JNI_EXIT("I", baseEnv(env)->UnregisterNatives(env, clazz));
1838}
1839
1840static jint Check_MonitorEnter(JNIEnv* env, jobject obj) {
1841    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1842    return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorEnter(env, obj));
1843}
1844
1845static jint Check_MonitorExit(JNIEnv* env, jobject obj) {
1846    CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, obj);
1847    return CHECK_JNI_EXIT("I", baseEnv(env)->MonitorExit(env, obj));
1848}
1849
1850static jint Check_GetJavaVM(JNIEnv *env, JavaVM **vm) {
1851    CHECK_JNI_ENTRY(kFlag_Default, "Ep", env, vm);
1852    return CHECK_JNI_EXIT("I", baseEnv(env)->GetJavaVM(env, vm));
1853}
1854
1855static void Check_GetStringRegion(JNIEnv* env, jstring str, jsize start, jsize len, jchar* buf) {
1856    CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf);
1857    baseEnv(env)->GetStringRegion(env, str, start, len, buf);
1858    CHECK_JNI_EXIT_VOID();
1859}
1860
1861static void Check_GetStringUTFRegion(JNIEnv* env, jstring str, jsize start, jsize len, char* buf) {
1862    CHECK_JNI_ENTRY(kFlag_CritOkay, "EsIIp", env, str, start, len, buf);
1863    baseEnv(env)->GetStringUTFRegion(env, str, start, len, buf);
1864    CHECK_JNI_EXIT_VOID();
1865}
1866
1867static void* Check_GetPrimitiveArrayCritical(JNIEnv* env, jarray array, jboolean* isCopy) {
1868    CHECK_JNI_ENTRY(kFlag_CritGet, "Eap", env, array, isCopy);
1869    void* result = baseEnv(env)->GetPrimitiveArrayCritical(env, array, isCopy);
1870    if (gDvmJni.forceCopy && result != NULL) {
1871        result = createGuardedPACopy(env, array, isCopy);
1872    }
1873    return CHECK_JNI_EXIT("p", result);
1874}
1875
1876static void Check_ReleasePrimitiveArrayCritical(JNIEnv* env, jarray array, void* carray, jint mode)
1877{
1878    CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Eapr", env, array, carray, mode);
1879    sc.checkNonNull(carray);
1880    if (gDvmJni.forceCopy) {
1881        carray = releaseGuardedPACopy(env, array, carray, mode);
1882    }
1883    baseEnv(env)->ReleasePrimitiveArrayCritical(env, array, carray, mode);
1884    CHECK_JNI_EXIT_VOID();
1885}
1886
1887static const jchar* Check_GetStringCritical(JNIEnv* env, jstring string, jboolean* isCopy) {
1888    CHECK_JNI_ENTRY(kFlag_CritGet, "Esp", env, string, isCopy);
1889    const jchar* result = baseEnv(env)->GetStringCritical(env, string, isCopy);
1890    if (gDvmJni.forceCopy && result != NULL) {
1891        ScopedJniThreadState ts(env);
1892        StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, string);
1893        int byteCount = strObj->length() * 2;
1894        result = (const jchar*) GuardedCopy::create(result, byteCount, false);
1895        if (isCopy != NULL) {
1896            *isCopy = JNI_TRUE;
1897        }
1898    }
1899    return CHECK_JNI_EXIT("p", result);
1900}
1901
1902static void Check_ReleaseStringCritical(JNIEnv* env, jstring string, const jchar* carray) {
1903    CHECK_JNI_ENTRY(kFlag_CritRelease | kFlag_ExcepOkay, "Esp", env, string, carray);
1904    sc.checkNonNull(carray);
1905    if (gDvmJni.forceCopy) {
1906        if (!GuardedCopy::check(carray, false)) {
1907            LOGE("JNI: failed guarded copy check in ReleaseStringCritical");
1908            abortMaybe();
1909            return;
1910        }
1911        carray = (const jchar*) GuardedCopy::destroy((jchar*)carray);
1912    }
1913    baseEnv(env)->ReleaseStringCritical(env, string, carray);
1914    CHECK_JNI_EXIT_VOID();
1915}
1916
1917static jweak Check_NewWeakGlobalRef(JNIEnv* env, jobject obj) {
1918    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1919    return CHECK_JNI_EXIT("L", baseEnv(env)->NewWeakGlobalRef(env, obj));
1920}
1921
1922static void Check_DeleteWeakGlobalRef(JNIEnv* env, jweak obj) {
1923    CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, obj);
1924    baseEnv(env)->DeleteWeakGlobalRef(env, obj);
1925    CHECK_JNI_EXIT_VOID();
1926}
1927
1928static jboolean Check_ExceptionCheck(JNIEnv* env) {
1929    CHECK_JNI_ENTRY(kFlag_CritOkay | kFlag_ExcepOkay, "E", env);
1930    return CHECK_JNI_EXIT("b", baseEnv(env)->ExceptionCheck(env));
1931}
1932
1933static jobjectRefType Check_GetObjectRefType(JNIEnv* env, jobject obj) {
1934    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, obj);
1935    // TODO: proper decoding of jobjectRefType!
1936    return CHECK_JNI_EXIT("I", baseEnv(env)->GetObjectRefType(env, obj));
1937}
1938
1939static jobject Check_NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
1940    CHECK_JNI_ENTRY(kFlag_Default, "EpJ", env, address, capacity);
1941    if (address == NULL || capacity < 0) {
1942        LOGW("JNI WARNING: invalid values for address (%p) or capacity (%ld)",
1943            address, (long) capacity);
1944        abortMaybe();
1945        return NULL;
1946    }
1947    return CHECK_JNI_EXIT("L", baseEnv(env)->NewDirectByteBuffer(env, address, capacity));
1948}
1949
1950static void* Check_GetDirectBufferAddress(JNIEnv* env, jobject buf) {
1951    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf);
1952    // TODO: check that 'buf' is a java.nio.Buffer.
1953    return CHECK_JNI_EXIT("p", baseEnv(env)->GetDirectBufferAddress(env, buf));
1954}
1955
1956static jlong Check_GetDirectBufferCapacity(JNIEnv* env, jobject buf) {
1957    CHECK_JNI_ENTRY(kFlag_Default, "EL", env, buf);
1958    // TODO: check that 'buf' is a java.nio.Buffer.
1959    return CHECK_JNI_EXIT("J", baseEnv(env)->GetDirectBufferCapacity(env, buf));
1960}
1961
1962
1963/*
1964 * ===========================================================================
1965 *      JNI invocation functions
1966 * ===========================================================================
1967 */
1968
1969static jint Check_DestroyJavaVM(JavaVM* vm) {
1970    ScopedCheck sc(false, __FUNCTION__);
1971    sc.check(true, "v", vm);
1972    return CHECK_JNI_EXIT("I", baseVm(vm)->DestroyJavaVM(vm));
1973}
1974
1975static jint Check_AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
1976    ScopedCheck sc(false, __FUNCTION__);
1977    sc.check(true, "vpp", vm, p_env, thr_args);
1978    return CHECK_JNI_EXIT("I", baseVm(vm)->AttachCurrentThread(vm, p_env, thr_args));
1979}
1980
1981static jint Check_AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
1982    ScopedCheck sc(false, __FUNCTION__);
1983    sc.check(true, "vpp", vm, p_env, thr_args);
1984    return CHECK_JNI_EXIT("I", baseVm(vm)->AttachCurrentThreadAsDaemon(vm, p_env, thr_args));
1985}
1986
1987static jint Check_DetachCurrentThread(JavaVM* vm) {
1988    ScopedCheck sc(true, __FUNCTION__);
1989    sc.check(true, "v", vm);
1990    return CHECK_JNI_EXIT("I", baseVm(vm)->DetachCurrentThread(vm));
1991}
1992
1993static jint Check_GetEnv(JavaVM* vm, void** env, jint version) {
1994    ScopedCheck sc(true, __FUNCTION__);
1995    sc.check(true, "v", vm);
1996    return CHECK_JNI_EXIT("I", baseVm(vm)->GetEnv(vm, env, version));
1997}
1998
1999
2000/*
2001 * ===========================================================================
2002 *      Function tables
2003 * ===========================================================================
2004 */
2005
2006static const struct JNINativeInterface gCheckNativeInterface = {
2007    NULL,
2008    NULL,
2009    NULL,
2010    NULL,
2011
2012    Check_GetVersion,
2013
2014    Check_DefineClass,
2015    Check_FindClass,
2016
2017    Check_FromReflectedMethod,
2018    Check_FromReflectedField,
2019    Check_ToReflectedMethod,
2020
2021    Check_GetSuperclass,
2022    Check_IsAssignableFrom,
2023
2024    Check_ToReflectedField,
2025
2026    Check_Throw,
2027    Check_ThrowNew,
2028    Check_ExceptionOccurred,
2029    Check_ExceptionDescribe,
2030    Check_ExceptionClear,
2031    Check_FatalError,
2032
2033    Check_PushLocalFrame,
2034    Check_PopLocalFrame,
2035
2036    Check_NewGlobalRef,
2037    Check_DeleteGlobalRef,
2038    Check_DeleteLocalRef,
2039    Check_IsSameObject,
2040    Check_NewLocalRef,
2041    Check_EnsureLocalCapacity,
2042
2043    Check_AllocObject,
2044    Check_NewObject,
2045    Check_NewObjectV,
2046    Check_NewObjectA,
2047
2048    Check_GetObjectClass,
2049    Check_IsInstanceOf,
2050
2051    Check_GetMethodID,
2052
2053    Check_CallObjectMethod,
2054    Check_CallObjectMethodV,
2055    Check_CallObjectMethodA,
2056    Check_CallBooleanMethod,
2057    Check_CallBooleanMethodV,
2058    Check_CallBooleanMethodA,
2059    Check_CallByteMethod,
2060    Check_CallByteMethodV,
2061    Check_CallByteMethodA,
2062    Check_CallCharMethod,
2063    Check_CallCharMethodV,
2064    Check_CallCharMethodA,
2065    Check_CallShortMethod,
2066    Check_CallShortMethodV,
2067    Check_CallShortMethodA,
2068    Check_CallIntMethod,
2069    Check_CallIntMethodV,
2070    Check_CallIntMethodA,
2071    Check_CallLongMethod,
2072    Check_CallLongMethodV,
2073    Check_CallLongMethodA,
2074    Check_CallFloatMethod,
2075    Check_CallFloatMethodV,
2076    Check_CallFloatMethodA,
2077    Check_CallDoubleMethod,
2078    Check_CallDoubleMethodV,
2079    Check_CallDoubleMethodA,
2080    Check_CallVoidMethod,
2081    Check_CallVoidMethodV,
2082    Check_CallVoidMethodA,
2083
2084    Check_CallNonvirtualObjectMethod,
2085    Check_CallNonvirtualObjectMethodV,
2086    Check_CallNonvirtualObjectMethodA,
2087    Check_CallNonvirtualBooleanMethod,
2088    Check_CallNonvirtualBooleanMethodV,
2089    Check_CallNonvirtualBooleanMethodA,
2090    Check_CallNonvirtualByteMethod,
2091    Check_CallNonvirtualByteMethodV,
2092    Check_CallNonvirtualByteMethodA,
2093    Check_CallNonvirtualCharMethod,
2094    Check_CallNonvirtualCharMethodV,
2095    Check_CallNonvirtualCharMethodA,
2096    Check_CallNonvirtualShortMethod,
2097    Check_CallNonvirtualShortMethodV,
2098    Check_CallNonvirtualShortMethodA,
2099    Check_CallNonvirtualIntMethod,
2100    Check_CallNonvirtualIntMethodV,
2101    Check_CallNonvirtualIntMethodA,
2102    Check_CallNonvirtualLongMethod,
2103    Check_CallNonvirtualLongMethodV,
2104    Check_CallNonvirtualLongMethodA,
2105    Check_CallNonvirtualFloatMethod,
2106    Check_CallNonvirtualFloatMethodV,
2107    Check_CallNonvirtualFloatMethodA,
2108    Check_CallNonvirtualDoubleMethod,
2109    Check_CallNonvirtualDoubleMethodV,
2110    Check_CallNonvirtualDoubleMethodA,
2111    Check_CallNonvirtualVoidMethod,
2112    Check_CallNonvirtualVoidMethodV,
2113    Check_CallNonvirtualVoidMethodA,
2114
2115    Check_GetFieldID,
2116
2117    Check_GetObjectField,
2118    Check_GetBooleanField,
2119    Check_GetByteField,
2120    Check_GetCharField,
2121    Check_GetShortField,
2122    Check_GetIntField,
2123    Check_GetLongField,
2124    Check_GetFloatField,
2125    Check_GetDoubleField,
2126    Check_SetObjectField,
2127    Check_SetBooleanField,
2128    Check_SetByteField,
2129    Check_SetCharField,
2130    Check_SetShortField,
2131    Check_SetIntField,
2132    Check_SetLongField,
2133    Check_SetFloatField,
2134    Check_SetDoubleField,
2135
2136    Check_GetStaticMethodID,
2137
2138    Check_CallStaticObjectMethod,
2139    Check_CallStaticObjectMethodV,
2140    Check_CallStaticObjectMethodA,
2141    Check_CallStaticBooleanMethod,
2142    Check_CallStaticBooleanMethodV,
2143    Check_CallStaticBooleanMethodA,
2144    Check_CallStaticByteMethod,
2145    Check_CallStaticByteMethodV,
2146    Check_CallStaticByteMethodA,
2147    Check_CallStaticCharMethod,
2148    Check_CallStaticCharMethodV,
2149    Check_CallStaticCharMethodA,
2150    Check_CallStaticShortMethod,
2151    Check_CallStaticShortMethodV,
2152    Check_CallStaticShortMethodA,
2153    Check_CallStaticIntMethod,
2154    Check_CallStaticIntMethodV,
2155    Check_CallStaticIntMethodA,
2156    Check_CallStaticLongMethod,
2157    Check_CallStaticLongMethodV,
2158    Check_CallStaticLongMethodA,
2159    Check_CallStaticFloatMethod,
2160    Check_CallStaticFloatMethodV,
2161    Check_CallStaticFloatMethodA,
2162    Check_CallStaticDoubleMethod,
2163    Check_CallStaticDoubleMethodV,
2164    Check_CallStaticDoubleMethodA,
2165    Check_CallStaticVoidMethod,
2166    Check_CallStaticVoidMethodV,
2167    Check_CallStaticVoidMethodA,
2168
2169    Check_GetStaticFieldID,
2170
2171    Check_GetStaticObjectField,
2172    Check_GetStaticBooleanField,
2173    Check_GetStaticByteField,
2174    Check_GetStaticCharField,
2175    Check_GetStaticShortField,
2176    Check_GetStaticIntField,
2177    Check_GetStaticLongField,
2178    Check_GetStaticFloatField,
2179    Check_GetStaticDoubleField,
2180
2181    Check_SetStaticObjectField,
2182    Check_SetStaticBooleanField,
2183    Check_SetStaticByteField,
2184    Check_SetStaticCharField,
2185    Check_SetStaticShortField,
2186    Check_SetStaticIntField,
2187    Check_SetStaticLongField,
2188    Check_SetStaticFloatField,
2189    Check_SetStaticDoubleField,
2190
2191    Check_NewString,
2192
2193    Check_GetStringLength,
2194    Check_GetStringChars,
2195    Check_ReleaseStringChars,
2196
2197    Check_NewStringUTF,
2198    Check_GetStringUTFLength,
2199    Check_GetStringUTFChars,
2200    Check_ReleaseStringUTFChars,
2201
2202    Check_GetArrayLength,
2203    Check_NewObjectArray,
2204    Check_GetObjectArrayElement,
2205    Check_SetObjectArrayElement,
2206
2207    Check_NewBooleanArray,
2208    Check_NewByteArray,
2209    Check_NewCharArray,
2210    Check_NewShortArray,
2211    Check_NewIntArray,
2212    Check_NewLongArray,
2213    Check_NewFloatArray,
2214    Check_NewDoubleArray,
2215
2216    Check_GetBooleanArrayElements,
2217    Check_GetByteArrayElements,
2218    Check_GetCharArrayElements,
2219    Check_GetShortArrayElements,
2220    Check_GetIntArrayElements,
2221    Check_GetLongArrayElements,
2222    Check_GetFloatArrayElements,
2223    Check_GetDoubleArrayElements,
2224
2225    Check_ReleaseBooleanArrayElements,
2226    Check_ReleaseByteArrayElements,
2227    Check_ReleaseCharArrayElements,
2228    Check_ReleaseShortArrayElements,
2229    Check_ReleaseIntArrayElements,
2230    Check_ReleaseLongArrayElements,
2231    Check_ReleaseFloatArrayElements,
2232    Check_ReleaseDoubleArrayElements,
2233
2234    Check_GetBooleanArrayRegion,
2235    Check_GetByteArrayRegion,
2236    Check_GetCharArrayRegion,
2237    Check_GetShortArrayRegion,
2238    Check_GetIntArrayRegion,
2239    Check_GetLongArrayRegion,
2240    Check_GetFloatArrayRegion,
2241    Check_GetDoubleArrayRegion,
2242    Check_SetBooleanArrayRegion,
2243    Check_SetByteArrayRegion,
2244    Check_SetCharArrayRegion,
2245    Check_SetShortArrayRegion,
2246    Check_SetIntArrayRegion,
2247    Check_SetLongArrayRegion,
2248    Check_SetFloatArrayRegion,
2249    Check_SetDoubleArrayRegion,
2250
2251    Check_RegisterNatives,
2252    Check_UnregisterNatives,
2253
2254    Check_MonitorEnter,
2255    Check_MonitorExit,
2256
2257    Check_GetJavaVM,
2258
2259    Check_GetStringRegion,
2260    Check_GetStringUTFRegion,
2261
2262    Check_GetPrimitiveArrayCritical,
2263    Check_ReleasePrimitiveArrayCritical,
2264
2265    Check_GetStringCritical,
2266    Check_ReleaseStringCritical,
2267
2268    Check_NewWeakGlobalRef,
2269    Check_DeleteWeakGlobalRef,
2270
2271    Check_ExceptionCheck,
2272
2273    Check_NewDirectByteBuffer,
2274    Check_GetDirectBufferAddress,
2275    Check_GetDirectBufferCapacity,
2276
2277    Check_GetObjectRefType
2278};
2279
2280static const struct JNIInvokeInterface gCheckInvokeInterface = {
2281    NULL,
2282    NULL,
2283    NULL,
2284
2285    Check_DestroyJavaVM,
2286    Check_AttachCurrentThread,
2287    Check_DetachCurrentThread,
2288
2289    Check_GetEnv,
2290
2291    Check_AttachCurrentThreadAsDaemon,
2292};
2293
2294/*
2295 * Replace the normal table with the checked table.
2296 */
2297void dvmUseCheckedJniEnv(JNIEnvExt* pEnv) {
2298    assert(pEnv->funcTable != &gCheckNativeInterface);
2299    pEnv->baseFuncTable = pEnv->funcTable;
2300    pEnv->funcTable = &gCheckNativeInterface;
2301}
2302
2303/*
2304 * Replace the normal table with the checked table.
2305 */
2306void dvmUseCheckedJniVm(JavaVMExt* pVm) {
2307    assert(pVm->funcTable != &gCheckInvokeInterface);
2308    pVm->baseFuncTable = pVm->funcTable;
2309    pVm->funcTable = &gCheckInvokeInterface;
2310}
2311