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