demo:
if(env->ExcetionCheck()) {
env->ExcetionClear();
}
http://aospxref.com/android-10.0.0_r47/xref/art/runtime/jni/check_jni.cc#2020
static jboolean ExceptionCheck(JNIEnv* env) {
CHECK_ATTACHED_THREAD(__FUNCTION__, JNI_FALSE);
ScopedObjectAccess soa(env);
ScopedCheck sc(kFlag_CritOkay | kFlag_ExcepOkay, __FUNCTION__);
JniValueType args[1] = {{.E = env}};
if (sc.Check(soa, true, "E", args)) { // 会check下是否为异常
JniValueType result;
result.b = baseEnv(env)->ExceptionCheck(env); // 然后通过顶层的env来捕获这个有异常
if (sc.Check(soa, false, "b", &result)) {
return result.b;
}
}
return JNI_FALSE;
}
http://aospxref.com/android-10.0.0_r47/xref/art/runtime/jni/check_jni.cc#535
/**
* The format string is a sequence of the following characters,
* and must be followed by arguments of the corresponding types
* in the same order.
*
* Java primitive types:
* B - jbyte
* C - jchar
* D - jdouble
* F - jfloat
* I - jint
* J - jlong
* S - jshort
* Z - jboolean (shown as true and false)
* V - void
*
* Java reference types:
* L - jobject
* a - jarray
* c - jclass
* s - jstring
*
* JNI types:
* b - jboolean (shown as JNI_TRUE and JNI_FALSE)
* f - jfieldID
* m - jmethodID
* p - void*
* r - jint (for release mode arguments)
* u - const char* (Modified UTF-8)
* z - jsize (for lengths; use i if negative values are okay)
* v - JavaVM*
* E - JNIEnv*
* . - VarArgs* for Jni calls with variable length arguments
*
* Use the kFlag_NullableUtf flag where 'u' field(s) are nullable.
*/
bool Check(ScopedObjectAccess& soa, bool entry, const char* fmt, JniValueType* args)
REQUIRES_SHARED(Locks::mutator_lock_) {
ArtMethod* traceMethod = nullptr;
if (has_method_ && soa.Vm()->IsTracingEnabled()) {
// We need to guard some of the invocation interface's calls: a bad caller might
// use DetachCurrentThread or GetEnv on a thread that's not yet attached.
Thread* self = Thread::Current();
if ((flags_ & kFlag_Invocation) == 0 || self != nullptr) {
traceMethod = self->GetCurrentMethod(nullptr);
}
}
if (((flags_ & kFlag_ForceTrace) != 0) ||
(traceMethod != nullptr && soa.Vm()->ShouldTrace(traceMethod))) {
std::string msg;
for (size_t i = 0; fmt[i] != '\0'; ++i) {
TracePossibleHeapValue(soa, entry, fmt[i], args[i], &msg);
if (fmt[i + 1] != '\0') {
StringAppendF(&msg, ", ");
}
}
if ((flags_ & kFlag_ForceTrace) != 0) {
LOG(INFO) << "JNI: call to " << function_name_ << "(" << msg << ")";
} else if (entry) {
if (has_method_) {
std::string methodName(ArtMethod::PrettyMethod(traceMethod, false));
LOG(INFO) << "JNI: " << methodName << " -> " << function_name_ << "(" << msg << ")";
indent_ = methodName.size() + 1;
} else {
LOG(INFO) << "JNI: -> " << function_name_ << "(" << msg << ")";
indent_ = 0;
}
} else {
LOG(INFO) << StringPrintf("JNI: %*s<- %s returned %s", indent_, "", function_name_, msg.c_str());
}
}
// We always do the thorough checks on entry, and never on exit...
if (entry) {
for (size_t i = 0; fmt[i] != '\0'; ++i) {
if (!CheckPossibleHeapValue(soa, fmt[i], args[i])) {
return false;
}
}
}
return true;
}