OSDN Git Service

merge in klp-release history after reset to klp-dev
[android-x86/dalvik.git] / vm / CheckJni.cpp
index bb32348..dac242a 100644 (file)
@@ -68,10 +68,10 @@ static void checkCallResultCommon(const u4* args, const JValue* pResult,
     const Object* resultObj = (const Object*) pResult->l;
 
     if (resultObj == kInvalidIndirectRefObject) {
-        LOGW("JNI WARNING: invalid reference returned from native code");
+        ALOGW("JNI WARNING: invalid reference returned from native code");
         const Method* method = dvmGetCurrentJNIMethod();
         char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
-        LOGW("             in %s.%s:%s", method->clazz->descriptor, method->name, desc);
+        ALOGW("             in %s.%s:%s", method->clazz->descriptor, method->name, desc);
         free(desc);
         abortMaybe();
         return;
@@ -103,17 +103,17 @@ static void checkCallResultCommon(const u4* args, const JValue* pResult,
          */
         ClassObject* declClazz = dvmFindClassNoInit(declType, method->clazz->classLoader);
         if (declClazz == NULL) {
-            LOGW("JNI WARNING: method declared to return '%s' returned '%s'",
+            ALOGW("JNI WARNING: method declared to return '%s' returned '%s'",
                 declType, objType);
-            LOGW("             failed in %s.%s ('%s' not found)",
+            ALOGW("             failed in %s.%s ('%s' not found)",
                 method->clazz->descriptor, method->name, declType);
             abortMaybe();
             return;
         }
         if (!dvmInstanceof(objClazz, declClazz)) {
-            LOGW("JNI WARNING: method declared to return '%s' returned '%s'",
+            ALOGW("JNI WARNING: method declared to return '%s' returned '%s'",
                 declType, objType);
-            LOGW("             failed in %s.%s",
+            ALOGW("             failed in %s.%s",
                 method->clazz->descriptor, method->name);
             abortMaybe();
             return;
@@ -162,20 +162,20 @@ static inline const JNIInvokeInterface* baseVm(JavaVM* vm) {
     return ((JavaVMExt*) vm)->baseFuncTable;
 }
 
-class ScopedJniThreadState {
+class ScopedCheckJniThreadState {
 public:
-    explicit ScopedJniThreadState(JNIEnv* env) {
+    explicit ScopedCheckJniThreadState(JNIEnv* env) {
         dvmChangeStatus(NULL, THREAD_RUNNING);
     }
 
-    ~ScopedJniThreadState() {
+    ~ScopedCheckJniThreadState() {
         dvmChangeStatus(NULL, THREAD_NATIVE);
     }
 
 private:
     // Disallow copy and assignment.
-    ScopedJniThreadState(const ScopedJniThreadState&);
-    void operator=(const ScopedJniThreadState&);
+    ScopedCheckJniThreadState(const ScopedCheckJniThreadState&);
+    void operator=(const ScopedCheckJniThreadState&);
 };
 
 /*
@@ -230,16 +230,16 @@ public:
      */
     void checkClassName(const char* className) {
         if (!dexIsValidClassName(className, false)) {
-            LOGW("JNI WARNING: illegal class name '%s' (%s)", className, mFunctionName);
-            LOGW("             (should be formed like 'dalvik/system/DexFile')");
-            LOGW("             or '[Ldalvik/system/DexFile;' or '[[B')");
+            ALOGW("JNI WARNING: illegal class name '%s' (%s)", className, mFunctionName);
+            ALOGW("             (should be formed like 'dalvik/system/DexFile')");
+            ALOGW("             or '[Ldalvik/system/DexFile;' or '[[B')");
             abortMaybe();
         }
     }
 
     void checkFieldTypeForGet(jfieldID fid, const char* expectedSignature, bool isStatic) {
         if (fid == NULL) {
-            LOGW("JNI WARNING: null jfieldID");
+            ALOGW("JNI WARNING: null jfieldID (%s)", mFunctionName);
             showLocation();
             abortMaybe();
         }
@@ -259,15 +259,15 @@ public:
 
         if (!printWarn && isStatic && !dvmIsStaticField(field)) {
             if (isStatic) {
-                LOGW("JNI WARNING: accessing non-static field %s as static", field->name);
+                ALOGW("JNI WARNING: accessing non-static field %s as static", field->name);
             } else {
-                LOGW("JNI WARNING: accessing static field %s as non-static", field->name);
+                ALOGW("JNI WARNING: accessing static field %s as non-static", field->name);
             }
             printWarn = true;
         }
 
         if (printWarn) {
-            LOGW("JNI WARNING: %s for field '%s' of expected type %s, got %s",
+            ALOGW("JNI WARNING: %s for field '%s' of expected type %s, got %s",
                     mFunctionName, field->name, expectedSignature, actualSignature);
             showLocation();
             abortMaybe();
@@ -282,7 +282,7 @@ public:
      */
     void checkFieldTypeForSet(jobject jobj, jfieldID fieldID, PrimitiveType prim, bool isStatic) {
         if (fieldID == NULL) {
-            LOGW("JNI WARNING: null jfieldID");
+            ALOGW("JNI WARNING: null jfieldID (%s)", mFunctionName);
             showLocation();
             abortMaybe();
         }
@@ -290,16 +290,16 @@ public:
         bool printWarn = false;
         Field* field = (Field*) fieldID;
         if ((field->signature[0] == 'L' || field->signature[0] == '[') && jobj != NULL) {
-            ScopedJniThreadState ts(mEnv);
-            Object* obj = dvmDecodeIndirectRef(mEnv, jobj);
+            ScopedCheckJniThreadState ts(mEnv);
+            Object* obj = dvmDecodeIndirectRef(self(), jobj);
             /*
              * If jobj is a weak global ref whose referent has been cleared,
              * obj will be NULL.  Otherwise, obj should always be non-NULL
              * and valid.
              */
             if (obj != NULL && !dvmIsHeapAddress(obj)) {
-                LOGW("JNI WARNING: field operation on invalid %s reference (%p)",
-                        indirectRefKindName(jobj), jobj);
+                ALOGW("JNI WARNING: field operation (%s) on invalid %s reference (%p)",
+                      mFunctionName, indirectRefKindName(jobj), jobj);
                 printWarn = true;
             } else {
                 ClassObject* fieldClass = dvmFindLoadedClass(field->signature);
@@ -309,20 +309,20 @@ public:
                 assert(objClass != NULL);
 
                 if (!dvmInstanceof(objClass, fieldClass)) {
-                    LOGW("JNI WARNING: set field '%s' expected type %s, got %s",
-                            field->name, field->signature, objClass->descriptor);
+                    ALOGW("JNI WARNING: %s for field '%s' expected type %s, got %s",
+                          mFunctionName, field->name, field->signature, objClass->descriptor);
                     printWarn = true;
                 }
             }
         } else if (dexGetPrimitiveTypeFromDescriptorChar(field->signature[0]) != prim) {
-            LOGW("JNI WARNING: %s for field '%s' expected type %s, got %s",
+            ALOGW("JNI WARNING: %s for field '%s' expected type %s, got %s",
                     mFunctionName, field->name, field->signature, primitiveTypeToName(prim));
             printWarn = true;
         } else if (isStatic && !dvmIsStaticField(field)) {
             if (isStatic) {
-                LOGW("JNI WARNING: accessing non-static field %s as static", field->name);
+                ALOGW("JNI WARNING: %s for non-static field '%s'", mFunctionName, field->name);
             } else {
-                LOGW("JNI WARNING: accessing static field %s as non-static", field->name);
+                ALOGW("JNI WARNING: %s for static field '%s'", mFunctionName, field->name);
             }
             printWarn = true;
         }
@@ -339,11 +339,11 @@ public:
      * Assumes "jobj" has already been validated.
      */
     void checkInstanceFieldID(jobject jobj, jfieldID fieldID) {
-        ScopedJniThreadState ts(mEnv);
+        ScopedCheckJniThreadState ts(mEnv);
 
-        Object* obj = dvmDecodeIndirectRef(mEnv, jobj);
+        Object* obj = dvmDecodeIndirectRef(self(), jobj);
         if (!dvmIsHeapAddress(obj)) {
-            LOGW("JNI ERROR: field operation on invalid reference (%p)", jobj);
+            ALOGW("JNI ERROR: %s on invalid reference (%p)", mFunctionName, jobj);
             dvmAbort();
         }
 
@@ -361,8 +361,8 @@ public:
             clazz = clazz->super;
         }
 
-        LOGW("JNI WARNING: instance fieldID %p not valid for class %s",
-                fieldID, obj->clazz->descriptor);
+        ALOGW("JNI WARNING: instance jfieldID %p not valid for class %s (%s)",
+              fieldID, obj->clazz->descriptor, mFunctionName);
         showLocation();
         abortMaybe();
     }
@@ -372,7 +372,7 @@ public:
      */
     void checkNonNull(const void* ptr) {
         if (ptr == NULL) {
-            LOGW("JNI WARNING: invalid null pointer (%s)", mFunctionName);
+            ALOGW("JNI WARNING: invalid null pointer (%s)", mFunctionName);
             abortMaybe();
         }
     }
@@ -386,20 +386,20 @@ public:
         bool printWarn = false;
 
         if (*expectedType != method->shorty[0]) {
-            LOGW("JNI WARNING: expected return type '%s'", expectedType);
+            ALOGW("JNI WARNING: %s expected return type '%s'", mFunctionName, expectedType);
             printWarn = true;
         } else if (isStatic && !dvmIsStaticMethod(method)) {
             if (isStatic) {
-                LOGW("JNI WARNING: calling non-static method with static call");
+                ALOGW("JNI WARNING: calling non-static method with static call %s", mFunctionName);
             } else {
-                LOGW("JNI WARNING: calling static method with non-static call");
+                ALOGW("JNI WARNING: calling static method with non-static call %s", mFunctionName);
             }
             printWarn = true;
         }
 
         if (printWarn) {
             char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
-            LOGW("             calling %s.%s %s", method->clazz->descriptor, method->name, desc);
+            ALOGW("             calling %s.%s %s", method->clazz->descriptor, method->name, desc);
             free(desc);
             showLocation();
             abortMaybe();
@@ -412,14 +412,14 @@ public:
      * Assumes "jclazz" has already been validated.
      */
     void checkStaticFieldID(jclass jclazz, jfieldID fieldID) {
-        ScopedJniThreadState ts(mEnv);
-        ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(mEnv, jclazz);
+        ScopedCheckJniThreadState ts(mEnv);
+        ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(self(), jclazz);
         StaticField* base = &clazz->sfields[0];
         int fieldCount = clazz->sfieldCount;
         if ((StaticField*) fieldID < base || (StaticField*) fieldID >= base + fieldCount) {
-            LOGW("JNI WARNING: static fieldID %p not valid for class %s",
-                    fieldID, clazz->descriptor);
-            LOGW("             base=%p count=%d", base, fieldCount);
+            ALOGW("JNI WARNING: static fieldID %p not valid for class %s (%s)",
+                  fieldID, clazz->descriptor, mFunctionName);
+            ALOGW("             base=%p count=%d", base, fieldCount);
             showLocation();
             abortMaybe();
         }
@@ -435,14 +435,14 @@ public:
      * Instances of "jclazz" must be instances of the method's declaring class.
      */
     void checkStaticMethod(jclass jclazz, jmethodID methodID) {
-        ScopedJniThreadState ts(mEnv);
+        ScopedCheckJniThreadState ts(mEnv);
 
-        ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(mEnv, jclazz);
+        ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(self(), jclazz);
         const Method* method = (const Method*) methodID;
 
         if (!dvmInstanceof(clazz, method->clazz)) {
-            LOGW("JNI WARNING: can't call static %s.%s on class %s",
-                    method->clazz->descriptor, method->name, clazz->descriptor);
+            ALOGW("JNI WARNING: can't call static %s.%s on class %s (%s)",
+                  method->clazz->descriptor, method->name, clazz->descriptor, mFunctionName);
             showLocation();
             // no abort?
         }
@@ -456,14 +456,14 @@ public:
      * will be handled automatically by the instanceof check.)
      */
     void checkVirtualMethod(jobject jobj, jmethodID methodID) {
-        ScopedJniThreadState ts(mEnv);
+        ScopedCheckJniThreadState ts(mEnv);
 
-        Object* obj = dvmDecodeIndirectRef(mEnv, jobj);
+        Object* obj = dvmDecodeIndirectRef(self(), jobj);
         const Method* method = (const Method*) methodID;
 
         if (!dvmInstanceof(obj->clazz, method->clazz)) {
-            LOGW("JNI WARNING: can't call %s.%s on instance of %s",
-                    method->clazz->descriptor, method->name, obj->clazz->descriptor);
+            ALOGW("JNI WARNING: can't call %s.%s on instance of %s (%s)",
+                  method->clazz->descriptor, method->name, obj->clazz->descriptor, mFunctionName);
             showLocation();
             abortMaybe();
         }
@@ -497,6 +497,7 @@ public:
      * m - jmethodID
      * p - void*
      * r - jint (for release mode arguments)
+     * t - thread args (for AttachCurrentThread)
      * u - const char* (modified UTF-8)
      * z - jsize (for lengths; use i if negative values are okay)
      * v - JavaVM*
@@ -579,7 +580,7 @@ public:
                     msg += (b ? "JNI_TRUE" : "JNI_FALSE");
                 } else if (ch == 'c') { // jclass
                     jclass jc = va_arg(ap, jclass);
-                    Object* c = dvmDecodeIndirectRef(mEnv, jc);
+                    Object* c = dvmDecodeIndirectRef(self(), jc);
                     if (c == NULL) {
                         msg += "NULL";
                     } else if (c == kInvalidIndirectRefObject || !dvmIsHeapAddress(c)) {
@@ -611,7 +612,7 @@ public:
                     if (!entry) {
                         StringAppendF(&msg, " (%p)", mid);
                     }
-                } else if (ch == 'p') { // void* ("pointer")
+                } else if (ch == 'p' || ch == 't') { // void* ("pointer" or "thread args")
                     void* p = va_arg(ap, void*);
                     if (p == NULL) {
                         msg += "NULL";
@@ -639,7 +640,7 @@ public:
                 } else if (ch == '.') {
                     msg += "...";
                 } else {
-                    LOGE("unknown trace format specifier %c", ch);
+                    ALOGE("unknown trace format specifier %c", ch);
                     dvmAbort();
                 }
                 if (*fmt) {
@@ -651,14 +652,14 @@ public:
             if (entry) {
                 if (mHasMethod) {
                     std::string methodName(dvmHumanReadableMethod(method, false));
-                    LOGI("JNI: %s -> %s(%s)", methodName.c_str(), mFunctionName, msg.c_str());
+                    ALOGI("JNI: %s -> %s(%s)", methodName.c_str(), mFunctionName, msg.c_str());
                     mIndent = methodName.size() + 1;
                 } else {
-                    LOGI("JNI: -> %s(%s)", mFunctionName, msg.c_str());
+                    ALOGI("JNI: -> %s(%s)", mFunctionName, msg.c_str());
                     mIndent = 0;
                 }
             } else {
-                LOGI("JNI: %*s<- %s returned %s", mIndent, "", mFunctionName, msg.c_str());
+                ALOGI("JNI: %*s<- %s returned %s", mIndent, "", mFunctionName, msg.c_str());
             }
         }
 
@@ -677,6 +678,8 @@ public:
                     checkReleaseMode(va_arg(ap, jint));
                 } else if (ch == 's') {
                     checkString(va_arg(ap, jstring));
+                } else if (ch == 't') {
+                    checkThreadArgs(va_arg(ap, void*));
                 } else if (ch == 'u') {
                     if ((mFlags & kFlag_Release) != 0) {
                         checkNonNull(va_arg(ap, const char*));
@@ -694,7 +697,7 @@ public:
                     va_arg(ap, long); // Skip this argument.
                 } else if (ch == '.') {
                 } else {
-                    LOGE("unknown check format specifier %c", ch);
+                    ALOGE("unknown check format specifier %c", ch);
                     dvmAbort();
                 }
             }
@@ -702,6 +705,11 @@ public:
         }
     }
 
+    // Only safe after checkThread returns.
+    Thread* self() {
+        return ((JNIEnvExt*) mEnv)->self;
+    }
+
 private:
     JNIEnv* mEnv;
     const char* mFunctionName;
@@ -729,23 +737,23 @@ private:
      */
     void checkArray(jarray jarr) {
         if (jarr == NULL) {
-            LOGW("JNI WARNING: received null array");
+            ALOGW("JNI WARNING: %s received null array", mFunctionName);
             showLocation();
             abortMaybe();
             return;
         }
 
-        ScopedJniThreadState ts(mEnv);
+        ScopedCheckJniThreadState ts(mEnv);
         bool printWarn = false;
 
-        Object* obj = dvmDecodeIndirectRef(mEnv, jarr);
+        Object* obj = dvmDecodeIndirectRef(self(), jarr);
         if (!dvmIsHeapAddress(obj)) {
-            LOGW("JNI WARNING: jarray is an invalid %s reference (%p)",
-            indirectRefKindName(jarr), jarr);
+            ALOGW("JNI WARNING: %s: jarray is an invalid %s reference (%p)",
+                  mFunctionName, indirectRefKindName(jarr), jarr);
             printWarn = true;
         } else if (obj->clazz->descriptor[0] != '[') {
-            LOGW("JNI WARNING: jarray arg has wrong type (expected array, got %s)",
-            obj->clazz->descriptor);
+            ALOGW("JNI WARNING: %s: jarray arg has wrong type (expected array, got %s)",
+                  mFunctionName, obj->clazz->descriptor);
             printWarn = true;
         }
 
@@ -761,7 +769,7 @@ private:
 
     void checkLengthPositive(jsize length) {
         if (length < 0) {
-            LOGW("JNI WARNING: negative jsize (%s)", mFunctionName);
+            ALOGW("JNI WARNING: negative jsize (%s)", mFunctionName);
             abortMaybe();
         }
     }
@@ -777,21 +785,22 @@ private:
             return;
         }
 
-        ScopedJniThreadState ts(mEnv);
+        ScopedCheckJniThreadState ts(mEnv);
 
         bool printWarn = false;
-        if (dvmGetJNIRefType(mEnv, jobj) == JNIInvalidRefType) {
-            LOGW("JNI WARNING: %p is not a valid JNI reference", jobj);
+        if (dvmGetJNIRefType(self(), jobj) == JNIInvalidRefType) {
+            ALOGW("JNI WARNING: %p is not a valid JNI reference (%s)", jobj, mFunctionName);
             printWarn = true;
         } else {
-            Object* obj = dvmDecodeIndirectRef(mEnv, jobj);
+            Object* obj = dvmDecodeIndirectRef(self(), jobj);
             if (obj == kInvalidIndirectRefObject) {
-                LOGW("JNI WARNING: native code passing in invalid reference %p", jobj);
+                ALOGW("JNI WARNING: native code passing in invalid reference %p (%s)",
+                      jobj, mFunctionName);
                 printWarn = true;
             } else if (obj != NULL && !dvmIsHeapAddress(obj)) {
                 // TODO: when we remove workAroundAppJniBugs, this should be impossible.
-                LOGW("JNI WARNING: native code passing in reference to invalid object %p %p",
-                        jobj, obj);
+                ALOGW("JNI WARNING: native code passing in reference to invalid object %p %p (%s)",
+                        jobj, obj, mFunctionName);
                 printWarn = true;
             }
         }
@@ -808,7 +817,7 @@ private:
      */
     void checkReleaseMode(jint mode) {
         if (mode != 0 && mode != JNI_COMMIT && mode != JNI_ABORT) {
-            LOGW("JNI WARNING: bad value for mode (%d) (%s)", mode, mFunctionName);
+            ALOGW("JNI WARNING: bad value for mode (%d) (%s)", mode, mFunctionName);
             abortMaybe();
         }
     }
@@ -817,6 +826,14 @@ private:
         checkInstance(s, gDvm.classJavaLangString, "jstring");
     }
 
+    void checkThreadArgs(void* thread_args) {
+        JavaVMAttachArgs* args = static_cast<JavaVMAttachArgs*>(thread_args);
+        if (args != NULL && args->version < JNI_VERSION_1_2) {
+            ALOGW("JNI WARNING: bad value for JNI version (%d) (%s)", args->version, mFunctionName);
+            abortMaybe();
+        }
+    }
+
     void checkThread(int flags) {
         // Get the *correct* JNIEnv by going through our TLS pointer.
         JNIEnvExt* threadEnv = dvmGetJNIEnvForThread();
@@ -827,17 +844,17 @@ private:
          */
         bool printWarn = false;
         if (threadEnv == NULL) {
-            LOGE("JNI ERROR: non-VM thread making JNI calls");
+            ALOGE("JNI ERROR: non-VM thread making JNI call (%s)", mFunctionName);
             // don't set printWarn -- it'll try to call showLocation()
             dvmAbort();
         } else if ((JNIEnvExt*) mEnv != threadEnv) {
             if (dvmThreadSelf()->threadId != threadEnv->envThreadId) {
-                LOGE("JNI: threadEnv != thread->env?");
+                ALOGE("JNI: threadEnv != thread->env? (%s)", mFunctionName);
                 dvmAbort();
             }
 
-            LOGW("JNI WARNING: threadid=%d using env from threadid=%d",
-                    threadEnv->envThreadId, ((JNIEnvExt*) mEnv)->envThreadId);
+            ALOGW("JNI WARNING: threadid=%d using env from threadid=%d (%s)",
+                  threadEnv->envThreadId, ((JNIEnvExt*) mEnv)->envThreadId, mFunctionName);
             printWarn = true;
 
             // If we're keeping broken code limping along, we need to suppress the abort...
@@ -849,8 +866,8 @@ private:
             //dvmThrowRuntimeException("invalid use of JNI env ptr");
         } else if (((JNIEnvExt*) mEnv)->self != dvmThreadSelf()) {
             /* correct JNIEnv*; make sure the "self" pointer is correct */
-            LOGE("JNI ERROR: env->self != thread-self (%p vs. %p)",
-                    ((JNIEnvExt*) mEnv)->self, dvmThreadSelf());
+            ALOGE("JNI ERROR: env->self != thread-self (%p vs. %p) (%s)",
+                  ((JNIEnvExt*) mEnv)->self, dvmThreadSelf(), mFunctionName);
             dvmAbort();
         }
 
@@ -863,8 +880,8 @@ private:
             break;
         case kFlag_CritBad:     // not okay to call
             if (threadEnv->critical) {
-                LOGW("JNI WARNING: threadid=%d using JNI after critical get",
-                        threadEnv->envThreadId);
+                ALOGW("JNI WARNING: threadid=%d using JNI after critical get (%s)",
+                      threadEnv->envThreadId, mFunctionName);
                 printWarn = true;
             }
             break;
@@ -875,8 +892,8 @@ private:
         case kFlag_CritRelease: // this is a "release" call
             threadEnv->critical--;
             if (threadEnv->critical < 0) {
-                LOGW("JNI WARNING: threadid=%d called too many crit releases",
-                        threadEnv->envThreadId);
+                ALOGW("JNI WARNING: threadid=%d called too many critical releases (%s)",
+                      threadEnv->envThreadId, mFunctionName);
                 printWarn = true;
             }
             break;
@@ -890,7 +907,7 @@ private:
          */
         bool printException = false;
         if ((flags & kFlag_ExcepOkay) == 0 && dvmCheckException(dvmThreadSelf())) {
-            LOGW("JNI WARNING: JNI method called with exception pending");
+            ALOGW("JNI WARNING: JNI function %s called with exception pending", mFunctionName);
             printWarn = true;
             printException = true;
         }
@@ -899,7 +916,7 @@ private:
             showLocation();
         }
         if (printException) {
-            LOGW("Pending exception is:");
+            ALOGW("Pending exception is:");
             dvmLogExceptionStackTrace();
         }
         if (printWarn) {
@@ -913,7 +930,7 @@ private:
     void checkUtfString(const char* bytes, bool nullable) {
         if (bytes == NULL) {
             if (!nullable) {
-                LOGW("JNI WARNING: non-nullable const char* was NULL");
+                ALOGW("JNI WARNING: non-nullable const char* was NULL (%s)", mFunctionName);
                 showLocation();
                 abortMaybe();
             }
@@ -923,8 +940,9 @@ private:
         const char* errorKind = NULL;
         u1 utf8 = checkUtfBytes(bytes, &errorKind);
         if (errorKind != NULL) {
-            LOGW("JNI WARNING: input is not valid Modified UTF-8: illegal %s byte %#x", errorKind, utf8);
-            LOGW("             string: '%s'", bytes);
+            ALOGW("JNI WARNING: %s input is not valid Modified UTF-8: illegal %s byte %#x",
+                  mFunctionName, errorKind, utf8);
+            ALOGW("             string: '%s'", bytes);
             showLocation();
             abortMaybe();
         }
@@ -939,23 +957,23 @@ private:
      */
     void checkInstance(jobject jobj, ClassObject* expectedClass, const char* argName) {
         if (jobj == NULL) {
-            LOGW("JNI WARNING: received null %s", argName);
+            ALOGW("JNI WARNING: received null %s (%s)", argName, mFunctionName);
             showLocation();
             abortMaybe();
             return;
         }
 
-        ScopedJniThreadState ts(mEnv);
+        ScopedCheckJniThreadState ts(mEnv);
         bool printWarn = false;
 
-        Object* obj = dvmDecodeIndirectRef(mEnv, jobj);
+        Object* obj = dvmDecodeIndirectRef(self(), jobj);
         if (!dvmIsHeapAddress(obj)) {
-            LOGW("JNI WARNING: %s is an invalid %s reference (%p)",
-                    argName, indirectRefKindName(jobj), jobj);
+            ALOGW("JNI WARNING: %s is an invalid %s reference (%p) (%s)",
+                  argName, indirectRefKindName(jobj), jobj, mFunctionName);
             printWarn = true;
         } else if (obj->clazz != expectedClass) {
-            LOGW("JNI WARNING: %s arg has wrong type (expected %s, got %s)",
-                    argName, expectedClass->descriptor, obj->clazz->descriptor);
+            ALOGW("JNI WARNING: %s arg has wrong type (expected %s, got %s) (%s)",
+                  argName, expectedClass->descriptor, obj->clazz->descriptor, mFunctionName);
             printWarn = true;
         }
 
@@ -1036,7 +1054,7 @@ private:
     void showLocation() {
         const Method* method = dvmGetCurrentJNIMethod();
         char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
-        LOGW("             in %s.%s:%s (%s)", method->clazz->descriptor, method->name, desc, mFunctionName);
+        ALOGW("             in %s.%s:%s (%s)", method->clazz->descriptor, method->name, desc, mFunctionName);
         free(desc);
     }
 
@@ -1134,7 +1152,7 @@ struct GuardedCopy {
         if (memcmp(&pExtra->magic, &kMagicCmp, 4) != 0) {
             u1 buf[4];
             memcpy(buf, &pExtra->magic, 4);
-            LOGE("JNI: guard magic does not match (found 0x%02x%02x%02x%02x) -- incorrect data pointer %p?",
+            ALOGE("JNI: guard magic does not match (found 0x%02x%02x%02x%02x) -- incorrect data pointer %p?",
                     buf[3], buf[2], buf[1], buf[0], dataBuf); /* assume little endian */
             return false;
         }
@@ -1145,7 +1163,7 @@ struct GuardedCopy {
         const u2* pat = (u2*) fullBuf;
         for (size_t i = sizeof(GuardedCopy) / 2; i < (kGuardLen / 2 - sizeof(GuardedCopy)) / 2; i++) {
             if (pat[i] != kGuardPattern) {
-                LOGE("JNI: guard pattern(1) disturbed at %p + %d", fullBuf, i*2);
+                ALOGE("JNI: guard pattern(1) disturbed at %p + %d", fullBuf, i*2);
                 return false;
             }
         }
@@ -1155,7 +1173,7 @@ struct GuardedCopy {
             /* odd byte; expected value depends on endian-ness of host */
             const u2 patSample = kGuardPattern;
             if (fullBuf[offset] != ((const u1*) &patSample)[1]) {
-                LOGE("JNI: guard pattern disturbed in odd byte after %p (+%d) 0x%02x 0x%02x",
+                ALOGE("JNI: guard pattern disturbed in odd byte after %p (+%d) 0x%02x 0x%02x",
                         fullBuf, offset, fullBuf[offset], ((const u1*) &patSample)[1]);
                 return false;
             }
@@ -1166,7 +1184,7 @@ struct GuardedCopy {
         pat = (u2*) (fullBuf + offset);
         for (size_t i = 0; i < kGuardLen / 4; i++) {
             if (pat[i] != kGuardPattern) {
-                LOGE("JNI: guard pattern(2) disturbed at %p + %d", fullBuf, offset + i*2);
+                ALOGE("JNI: guard pattern(2) disturbed at %p + %d", fullBuf, offset + i*2);
                 return false;
             }
         }
@@ -1180,7 +1198,7 @@ struct GuardedCopy {
             uLong adler = adler32(0L, Z_NULL, 0);
             adler = adler32(adler, (const Bytef*)dataBuf, len);
             if (pExtra->adler != adler) {
-                LOGE("JNI: buffer modified (0x%08lx vs 0x%08lx) at addr %p",
+                ALOGE("JNI: buffer modified (0x%08lx vs 0x%08lx) at addr %p",
                         pExtra->adler, adler, dataBuf);
                 return false;
             }
@@ -1193,7 +1211,7 @@ private:
     static u1* debugAlloc(size_t len) {
         void* result = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0);
         if (result == MAP_FAILED) {
-            LOGE("GuardedCopy::create mmap(%d) failed: %s", len, strerror(errno));
+            ALOGE("GuardedCopy::create mmap(%d) failed: %s", len, strerror(errno));
             dvmAbort();
         }
         return reinterpret_cast<u1*>(result);
@@ -1205,10 +1223,10 @@ private:
         // TODO: we could mprotect instead, and keep the allocation around for a while.
         // This would be even more expensive, but it might catch more errors.
         // if (mprotect(fullBuf, totalByteCount, PROT_NONE) != 0) {
-        //     LOGW("mprotect(PROT_NONE) failed: %s", strerror(errno));
+        //     ALOGW("mprotect(PROT_NONE) failed: %s", strerror(errno));
         // }
         if (munmap(fullBuf, totalByteCount) != 0) {
-            LOGW("munmap failed: %s", strerror(errno));
+            ALOGW("munmap failed: %s", strerror(errno));
             dvmAbort();
         }
     }
@@ -1253,9 +1271,9 @@ static int dvmPrimitiveTypeWidth(PrimitiveType primType) {
  * data are allowed.  Returns a pointer to the copied data.
  */
 static void* createGuardedPACopy(JNIEnv* env, const jarray jarr, jboolean* isCopy) {
-    ScopedJniThreadState ts(env);
+    ScopedCheckJniThreadState ts(env);
 
-    ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
+    ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(dvmThreadSelf(), jarr);
     PrimitiveType primType = arrObj->clazz->elementClass->primitiveType;
     int len = arrObj->length * dvmPrimitiveTypeWidth(primType);
     void* result = GuardedCopy::create(arrObj->contents, len, true);
@@ -1270,11 +1288,11 @@ static void* createGuardedPACopy(JNIEnv* env, const jarray jarr, jboolean* isCop
  * back into the VM, and may or may not release the underlying storage.
  */
 static void* releaseGuardedPACopy(JNIEnv* env, jarray jarr, void* dataBuf, int mode) {
-    ScopedJniThreadState ts(env);
-    ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(env, jarr);
+    ScopedCheckJniThreadState ts(env);
+    ArrayObject* arrObj = (ArrayObject*) dvmDecodeIndirectRef(dvmThreadSelf(), jarr);
 
     if (!GuardedCopy::check(dataBuf, true)) {
-        LOGE("JNI: failed guarded copy check in releaseGuardedPACopy");
+        ALOGE("JNI: failed guarded copy check in releaseGuardedPACopy");
         abortMaybe();
         return NULL;
     }
@@ -1420,9 +1438,9 @@ static jobject Check_NewGlobalRef(JNIEnv* env, jobject obj) {
 
 static void Check_DeleteGlobalRef(JNIEnv* env, jobject globalRef) {
     CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, globalRef);
-    if (globalRef != NULL && dvmGetJNIRefType(env, globalRef) != JNIGlobalRefType) {
-        LOGW("JNI WARNING: DeleteGlobalRef on non-global %p (type=%d)",
-                globalRef, dvmGetJNIRefType(env, globalRef));
+    if (globalRef != NULL && dvmGetJNIRefType(sc.self(), globalRef) != JNIGlobalRefType) {
+        ALOGW("JNI WARNING: DeleteGlobalRef on non-global %p (type=%d)",
+             globalRef, dvmGetJNIRefType(sc.self(), globalRef));
         abortMaybe();
     } else {
         baseEnv(env)->DeleteGlobalRef(env, globalRef);
@@ -1437,9 +1455,9 @@ static jobject Check_NewLocalRef(JNIEnv* env, jobject ref) {
 
 static void Check_DeleteLocalRef(JNIEnv* env, jobject localRef) {
     CHECK_JNI_ENTRY(kFlag_Default | kFlag_ExcepOkay, "EL", env, localRef);
-    if (localRef != NULL && dvmGetJNIRefType(env, localRef) != JNILocalRefType) {
-        LOGW("JNI WARNING: DeleteLocalRef on non-local %p (type=%d)",
-                localRef, dvmGetJNIRefType(env, localRef));
+    if (localRef != NULL && dvmGetJNIRefType(sc.self(), localRef) != JNILocalRefType) {
+        ALOGW("JNI WARNING: DeleteLocalRef on non-local %p (type=%d)",
+             localRef, dvmGetJNIRefType(sc.self(), localRef));
         abortMaybe();
     } else {
         baseEnv(env)->DeleteLocalRef(env, localRef);
@@ -1687,8 +1705,8 @@ static const jchar* Check_GetStringChars(JNIEnv* env, jstring string, jboolean*
     CHECK_JNI_ENTRY(kFlag_CritOkay, "Esp", env, string, isCopy);
     const jchar* result = baseEnv(env)->GetStringChars(env, string, isCopy);
     if (gDvmJni.forceCopy && result != NULL) {
-        ScopedJniThreadState ts(env);
-        StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, string);
+        ScopedCheckJniThreadState ts(env);
+        StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(dvmThreadSelf(), string);
         int byteCount = strObj->length() * 2;
         result = (const jchar*) GuardedCopy::create(result, byteCount, false);
         if (isCopy != NULL) {
@@ -1703,7 +1721,7 @@ static void Check_ReleaseStringChars(JNIEnv* env, jstring string, const jchar* c
     sc.checkNonNull(chars);
     if (gDvmJni.forceCopy) {
         if (!GuardedCopy::check(chars, false)) {
-            LOGE("JNI: failed guarded copy check in ReleaseStringChars");
+            ALOGE("JNI: failed guarded copy check in ReleaseStringChars");
             abortMaybe();
             return;
         }
@@ -1739,7 +1757,7 @@ static void Check_ReleaseStringUTFChars(JNIEnv* env, jstring string, const char*
     CHECK_JNI_ENTRY(kFlag_ExcepOkay | kFlag_Release, "Esu", env, string, utf); // TODO: show pointer and truncate string.
     if (gDvmJni.forceCopy) {
         if (!GuardedCopy::check(utf, false)) {
-            LOGE("JNI: failed guarded copy check in ReleaseStringUTFChars");
+            ALOGE("JNI: failed guarded copy check in ReleaseStringUTFChars");
             abortMaybe();
             return;
         }
@@ -1930,8 +1948,8 @@ static const jchar* Check_GetStringCritical(JNIEnv* env, jstring string, jboolea
     CHECK_JNI_ENTRY(kFlag_CritGet, "Esp", env, string, isCopy);
     const jchar* result = baseEnv(env)->GetStringCritical(env, string, isCopy);
     if (gDvmJni.forceCopy && result != NULL) {
-        ScopedJniThreadState ts(env);
-        StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(env, string);
+        ScopedCheckJniThreadState ts(env);
+        StringObject* strObj = (StringObject*) dvmDecodeIndirectRef(dvmThreadSelf(), string);
         int byteCount = strObj->length() * 2;
         result = (const jchar*) GuardedCopy::create(result, byteCount, false);
         if (isCopy != NULL) {
@@ -1946,7 +1964,7 @@ static void Check_ReleaseStringCritical(JNIEnv* env, jstring string, const jchar
     sc.checkNonNull(carray);
     if (gDvmJni.forceCopy) {
         if (!GuardedCopy::check(carray, false)) {
-            LOGE("JNI: failed guarded copy check in ReleaseStringCritical");
+            ALOGE("JNI: failed guarded copy check in ReleaseStringCritical");
             abortMaybe();
             return;
         }
@@ -1980,12 +1998,6 @@ static jobjectRefType Check_GetObjectRefType(JNIEnv* env, jobject obj) {
 
 static jobject Check_NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
     CHECK_JNI_ENTRY(kFlag_Default, "EpJ", env, address, capacity);
-    if (address == NULL || capacity < 0) {
-        LOGW("JNI WARNING: invalid values for address (%p) or capacity (%ld)",
-            address, (long) capacity);
-        abortMaybe();
-        return NULL;
-    }
     return CHECK_JNI_EXIT("L", baseEnv(env)->NewDirectByteBuffer(env, address, capacity));
 }
 
@@ -2016,13 +2028,13 @@ static jint Check_DestroyJavaVM(JavaVM* vm) {
 
 static jint Check_AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
     ScopedCheck sc(false, __FUNCTION__);
-    sc.check(true, "vpp", vm, p_env, thr_args);
+    sc.check(true, "vpt", vm, p_env, thr_args);
     return CHECK_JNI_EXIT("I", baseVm(vm)->AttachCurrentThread(vm, p_env, thr_args));
 }
 
 static jint Check_AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
     ScopedCheck sc(false, __FUNCTION__);
-    sc.check(true, "vpp", vm, p_env, thr_args);
+    sc.check(true, "vpt", vm, p_env, thr_args);
     return CHECK_JNI_EXIT("I", baseVm(vm)->AttachCurrentThreadAsDaemon(vm, p_env, thr_args));
 }