graph LR
解释执行-->异常投递-->|case Instruction::THROW|setException("异常对象赋值给Thread的tlsPtr_exception的成员变量")
解释执行-->异常处理-->HANDLE_PENDING_EXCEPTION-->|找到能处理该异常的指令码|ArtMethod::FindCatchBlock
机器码执行-->InstructionCodeGeneratorX86::VisitThrow-->artDeliverExceptionFromCode-->setException
artDeliverExceptionFromCode-->|找到异常处理处的指令位置|findCatch("exception_handler.FindCatch(exception);")
被抛出的异常对象赋值给Thread tlsPtr_exception的成员变量,异常投递的工作就算完成;
接下来就是异常处理的过程。以switch/case方式来解释执行的代码中,下面这个宏用于判断是否有异常发生并处理它。
Dex_instruction_list.h
#define DEX_INSTRUCTION_LIST(V) \
V(0x27, THROW, "throw", k11x, false, kIndexNone, kThrow, kVerifyRegA) \
interpreter_switch_impl.cc
template<bool do_access_check, bool transaction_active>
JValue ExecuteSwitchImpl(......) {
...... //该函数详情见10.2.3.1节
do {
dex_pc = inst->GetDexPc(insns);
......
inst_data = inst->Fetch16(0);
switch (inst->Opcode(inst_data)) { //switch/case方式执行不同的dex指令
......
case Instruction::THROW: { //抛异常
PREAMBLE();
Object* exception = shadow_frame.GetVRegReference( inst->VRegA_11x(inst_data));
if (UNLIKELY(exception == nullptr)) {
//Throw抛出的异常对象为空,则重新抛一个空指针异常
ThrowNullPointerException("throw with null exception");
} else if (.....) {.....}
else {
/*注意:Thread tlsPtr_有一个名为exception的成员变量,其类型为Throwable*。
其他代码逻辑要检查是否有异常发生的话,只要判断tlsPtr_exception是否为nullptr
即可。如果tlsPtr_ exception不为空指针,则表明有异常发生。
下面的SetException函数将把抛出的异常对象赋值给tlsPtr_exception*///main
self->SetException(exception->AsThrowable());
}
HANDLE_PENDING_EXCEPTION(); //检查是否有异常发生,并做对应处理。main
break;
}
.....
}
define HANDLE_PENDING_EXCEPTION() \
do { \
self->AllowThreadSuspension(); \
/*下面这个函数用于从当前正在执行的方法里找到对应的catch处理语句,如果能处理所抛出
的异常,则返回异常处理对应的dex指令码的位置*/
uint32_t found_dex_pc = FindNextInstructionFollowingException(self,\
shadow_frame, inst->GetDexPc(insns), instrumentation); \
//如果本方法无法处理这个异常,则要退出整个方法的执行
if (found_dex_pc == DexFile::kDexNoIndex) { \
......\
} \
return JValue(); /* 退出本方法的执行,调用者将继续检查并处理异常 */ \
} else { \
//如果本方法catch住了所抛出的异常,则找到对应的处理指令
int32_t displacement = static_cast<int32_t>(found_dex_pc) - \static_cast<int32_t>(dex_pc); \
inst = inst->RelativeAt(displacement); \
} \
} while (false)
interpreter_common.cc
uint32_t FindNextInstructionFollowingException(
Thread* self, ShadowFrame& shadow_frame, uint32_t dex_pc,
const instrumentation::Instrumentation* instrumentation) {
self->VerifyStack();
StackHandleScope<2> hs(self);
Handle<mirror::Throwable> exception(hs.NewHandle(self->GetException()));
......
bool clear_exception = false;
//调用ArtMethod的FindCatchBlock。
uint32_t found_dex_pc = shadow_frame.GetMethod()->FindCatchBlock(
hs.NewHandle(exception->GetClass()), dex_pc, &clear_exception);
if (found_dex_pc == DexFile::kDexNoIndex && instrumentation != nullptr) {
//如果本方法无法处理这个异常,则表示要进行栈回溯。此时将触发Instrumentation的
//MethodUnwindEvent函数
instrumentation->MethodUnwindEvent(self, shadow_frame.GetThisObject(),
shadow_frame.GetMethod(), dex_pc);
} else {......}
return found_dex_pc;
}
quick_entrypoints_x86.S
MACRO0(RETURN_OR_DELIVER_PENDING_EXCEPTION)
#检查Thread tlsPtr_ exception变量是否为空,如果不为空,则跳转到DELIVER_PENDING_EXCEPTION宏处,main
cmpl MACRO_LITERAL(0),%fs:THREAD_EXCEPTION_OFFSET
jne 1f
ret
1:
DELIVER_PENDING_EXCEPTION #异常处理宏
END_MACRO
MACRO0(DELIVER_PENDING_EXCEPTION) #异常处理宏定义
#该宏内部将设置tlsPtr_ managed_stack top_quick_frame_的值
SETUP_SAVE_ALL_CALLEE_SAVE_FRAME ebx, ebx
subl MACRO_LITERAL(12), %esp
pushl %fs:THREAD_SELF_OFFSET
#调用artDeliverPendingExceptionFromCode函数,main
call SYMBOL(artDeliverPendingExceptionFromCode)
UNREACHABLE
END_MACRO
quick_throw_entrypoints.cc
extern "C" NO_RETURN void artDeliverPendingExceptionFromCode(Thread* self) {
ScopedQuickEntrypointChecks sqec(self);
self->QuickDeliverException(); //调用Thread QuickDeliverException函数
}
code_generator_x86.cc
void InstructionCodeGeneratorX86::VisitThrow(HThrow* instruction) {
codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pDeliverException),
instruction,
instruction->GetDexPc(),
nullptr);
CheckEntrypointTypes<kQuickDeliverException, void, mirror::Object*>();
}
quick_entrypoints_x86.S
ONE_ARG_RUNTIME_EXCEPTION art_quick_deliver_exception, \
artDeliverExceptionFromCode #调用C++层artDeliverExceptionFromCode
//ONE_ARG_RUNTIME_EXCEPTION是一个宏,其内部调用SETUP_SAVE_CALLEE_SAVE_FRAME,
//由于artDeliverExceptionFromCode位于虚拟机执行层,所以需要设置tlsPtr_managed_stack top_quick_frame_
MACRO2(ONE_ARG_RUNTIME_EXCEPTION, c_name, cxx_name)
DEFINE_FUNCTION VAR(c_name)
SETUP_SAVE_ALL_CALLEE_SAVE_FRAME ebx, ebx mov %esp, %ecx
// Outgoing argument set up
subl MACRO_LITERAL(8), %esp
pushl %fs:THREAD_SELF_OFFSET
PUSH eax
call CALLVAR(cxx_name)
UNREACHABLE
END_FUNCTION VAR(c_name)
END_MACRO
quick_throw_entrypoints.cc
extern "C" NO_RETURN void artDeliverExceptionFromCode(
mirror::Throwable* exception, Thread* self){
ScopedQuickEntrypointChecks sqec(self);
if (exception == nullptr) {
self->ThrowNewException("Ljava/lang/NullPointerException;",
"throw with null exception");
} else {
self->SetException(exception); //设置tlsPtr_ exception
}
self->QuickDeliverException(); //还是调用Thread类的QuickDeliverException
}
thread.cc
void Thread::QuickDeliverException() {
mirror::Throwable* exception = GetException();
//判断是否为Deoptimize相关的异常。此处不讨论Deoptimize的情况,所以
//is_deoptimization为false
bool is_deoptimization = (exception == GetDeoptimizationException());
if (!is_deoptimization) {
instrumentation::Instrumentation* instrumentation =
Runtime::Current()->GetInstrumentation();
if (instrumentation->HasExceptionCaughtListeners() &&
IsExceptionThrownByCurrentMethod(exception)) {
StackHandleScope<1> hs(this);
HandleWrapper<mirror::Throwable> h_exception(hs.NewHandleWrapper(
&exception));
instrumentation->ExceptionCaughtEvent(this, exception);
}
......
}
ClearException();
QuickExceptionHandler exception_handler(this, is_deoptimization);
if (is_deoptimization) {
//DeoptimizeStack函数的详情见10.4.2.2节
exception_handler.DeoptimizeStack();
} else {
//FindCatch非常关键,它将找到异常处理处的指令位置(pc),main
exception_handler.FindCatch(exception);
}
exception_handler.UpdateInstrumentationStack();
exception_handler.DoLongJump(); //跳转到异常处理对应的地址
}
quick_exception_handler.cc
void QuickExceptionHandler::FindCatch(mirror::Throwable* exception) {
StackHandleScope<1> hs(self_);
Handle<mirror::Throwable> exception_ref(hs.NewHandle(exception));
//关键类
CatchBlockStackVisitor visitor(self_, context_, &exception_ref, this);
visitor.WalkStack(true); //输入参数为true
if (clear_exception_) {}
else {
self_->SetException(exception_ref.Get());
}
//如果异常处理的代码位于机器码中,则再补充设置一些信息。这部分内容和机器码编译有一些关系,建
//议读者暂时不要理会
if (*handler_quick_frame_ != nullptr &&
handler_method_header_ != nullptr &&
handler_method_header_->IsOptimized()) {
SetCatchEnvironmentForOptimizedHandler(&visitor);
}
}
class CatchBlockStackVisitor FINAL : public StackVisitor {
......
bool VisitFrame() (Locks::mutator_lock_) {//main
/*获取当前正在访问的方法。根据图10-14所示,我们依次会访问到Runtime ArtMethod、方法B、方
法A。最后将进入虚拟机执行X1。 */
ArtMethod* method = GetMethod();
exception_handler_->SetHandlerFrameDepth(GetFrameDepth());
//如果method为空,表示当前所访问的方法为虚拟机执行层
if (method == nullptr) {
/*①注意,如果if条件满足,则表明栈回溯到了虚拟机执行层,这时我们不能再继续回溯虚拟机执行层的函数了,只能先jump回(Quick-ExceptionHandler的主要功能就是long jump,即长跳转到目标指令位置)X1调用方法A的返回处。*/
exception_handler_->SetHandlerQuickFramePc(GetCurrentQuickFramePc());//返回X1中方法A的返回地址
exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame());
exception_handler_->SetHandlerMethodHeader(
GetCurrentOatQuickMethodHeader());
uint32_t next_dex_pc;
ArtMethod* next_art_method;
/*GetNextMethodAndDexPc函数内部也会做WalkStack进行栈回溯操作,找到紧挨着当前
虚拟机执行层中的上一个方法。在图10-14中,X1往上没有调用者了,所以下面这个函数
返回false。如果X1之上还有调用者,则返回那个函数的一些信息。 */
bool has_next = GetNextMethodAndDexPc(&next_art_method, &next_dex_pc);
exception_handler_->SetHandlerDexPc(next_dex_pc);
exception_handler_->SetHandlerMethod(next_art_method);
......
return false; // End stack walk.
}
//略过Runtime ArtMethod
if (method->IsRuntimeMethod()) { return true; }
/*从method中catch语句中找到是否有能处理该异常的地方。该函数和解释执行层中的FindNextInstruc-
tionFollowingException函数类似,请读者自行阅读它。假设图10-14中的方法B、方法A均无法
处理此异常,则HandleTryItems将返回true *///main
return HandleTryItems(method);
}
graph TB
mJavaVM.DetachCurrentThread-->Thread::Destroy-->Thread::HandleUncaughtExceptions-->|Jni调用java层Thread的uncaughtExceptionHandler|Thead.uncaughtExceptionHandler-->TheadGroup-->ThreadStaticUncaughtExceptionHandler
AndroidRuntime
void AndroidRuntime::start(const char* className,
const Vector<String8>& options, bool zygote){
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
//启动虚拟机
if (startVm(&mJavaVM, &env, zygote) != 0) { return; }
......
char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {..... }
else {
//假设startMeth是图10-14中的方法A
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {......}
else {
/*下面的CallStaciVoidMethod将触发图10-14的虚拟机执行X1,其内部调用方法
A。根据上文所述,Thread QuickDeliverException的执行完后,longjmp将跳
转到X1调用方法A返回后的指令处,就好像方法A执行完了一样(实际上没有)。
所以,下面的CallStaticVoidMethod将返回。 main*/
env->CallStaticVoidMethod(startClass, startMeth, strArray);
}
}
free(slashClassName);
if (mJavaVM->DetachCurrentThread() != JNI_OK)//main
ALOGW("Warning: unable to detach main thread\n");
if (mJavaVM->DestroyJavaVM() != 0)
ALOGW("Warning: VM did not shut down cleanly\n");
java_vm_ext.cc
static jint DetachCurrentThread(JavaVM* vm) {
......
JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm);
Runtime* runtime = raw_vm->GetRuntime();
runtime->DetachCurrentThread(); //内部将调用当前线程的Destroy方法,main
return JNI_OK;
}
Thread.cc
void Thread::Destroy() {
Thread* self = this;
......
if (tlsPtr_.opeer != nullptr) {
ScopedObjectAccess soa(self);
//调用为该线程设置的UncaughtExceptionHandler对象。感兴趣的读者可自行研究该函数。main
HandleUncaughtExceptions(soa);
RemoveFromThreadGroup(soa);
}
......
}
void Thread::HandleUncaughtExceptions(ScopedObjectAccess& soa) {
if (!IsExceptionPending()) {
return;
}
ScopedLocalRef<jobject> peer(tlsPtr_.jni_env, soa.AddLocalReference<jobject>(tlsPtr_.opeer));
ScopedThreadStateChange tsc(this, kNative);
// Get and clear the exception.
ScopedLocalRef<jthrowable> exception(tlsPtr_.jni_env, tlsPtr_.jni_env->ExceptionOccurred());
tlsPtr_.jni_env->ExceptionClear();
// If the thread has its own handler, use that.
ScopedLocalRef<jobject> handler(tlsPtr_.jni_env,
tlsPtr_.jni_env->GetObjectField(peer.get(),
WellKnownClasses::java_lang_Thread_uncaughtHandler));
if (handler.get() == nullptr) {
// Otherwise use the thread group's default handler.
handler.reset(tlsPtr_.jni_env->GetObjectField(peer.get(),
WellKnownClasses::java_lang_Thread_group));
}
// Call the handler.
tlsPtr_.jni_env->CallVoidMethod(handler.get(),//main
WellKnownClasses::java_lang_Thread__UncaughtExceptionHandler_uncaughtException,
peer.get(), exception.get());
// If the handler threw, clear that exception too.
tlsPtr_.jni_env->ExceptionClear();
}
Jni.h / jni_internal.cc
/*
* C++ object wrapper.
*
* This is usually overlaid on a C struct whose first element is a
* JNINativeInterface*. We rely somewhat on compiler behavior.
*/
struct _JNIEnv {
jthrowable ExceptionOccurred()
{ return functions->ExceptionOccurred(this); }
static jthrowable ExceptionOccurred(JNIEnv* env) {
ScopedObjectAccess soa(env);
mirror::Object* exception = soa.Self()->GetException();
return soa.AddLocalReference<jthrowable>(exception);
}
Thread.cc
{
...
// Every thread may have an associated JNI environment
JNIEnvExt* jni_env;
} tlsPtr_;
mirror::Throwable* GetException() const SHARED_REQUIRES(Locks::mutator_lock_) {
return tlsPtr_.exception;
}
bool IsExceptionPending() const {
return tlsPtr_.exception != nullptr;
}
// null unless explicitly set
private volatile UncaughtExceptionHandler uncaughtExceptionHandler;
public void uncaughtException(Thread t, Throwable e) {
if (parent != null) {
parent.uncaughtException(t, e);
} else {
Thread.UncaughtExceptionHandler ueh =
Thread.getDefaultUncaughtExceptionHandler();
if (ueh != null) {
ueh.uncaughtException(t, e);
} else if (!(e instanceof ThreadDeath)) {
System.err.print("Exception in thread \""
\+ t.getName() + "\" ");
e.printStackTrace(System.err);
}
}
}
// null unless explicitly set
private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;