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