원본 각도에서 안드로이드 시스템의 이상 포획 메커니즘이 어떻게 작동하는지 분석하다
우리는 하나의 예로 시작한다.
import android.app.Activity;
import android.os.Bundle;
public class MainActivity4 extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
throw new NullPointerException();
}
}
이 프로그램이 시작되면 다음과 같이 Logcat에 예외가 발생합니다.
10-10 16:44:16.200: W/dalvikvm(381): threadid=1: thread exiting with uncaught exception (group=0x41588d58)
10-10 16:44:16.200: W/System.err(381): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.sahadev.renren/com.sahadev.activitythemetest.MainActivity4}: java.lang.NullPointerException
10-10 16:44:16.200: W/System.err(381): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2263)
10-10 16:44:16.200: W/System.err(381): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2313)
10-10 16:44:16.200: W/System.err(381): at android.app.ActivityThread.access$800(ActivityThread.java:147)
10-10 16:44:16.200: W/System.err(381): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1226)
10-10 16:44:16.200: W/System.err(381): at android.os.Handler.dispatchMessage(Handler.java:102)
10-10 16:44:16.200: W/System.err(381): at android.os.Looper.loop(Looper.java:136)
10-10 16:44:16.200: W/System.err(381): at android.app.ActivityThread.main(ActivityThread.java:5137)
10-10 16:44:16.200: W/System.err(381): at java.lang.reflect.Method.invokeNative(Native Method)
10-10 16:44:16.200: W/System.err(381): at java.lang.reflect.Method.invoke(Method.java:515)
10-10 16:44:16.200: W/System.err(381): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:801)
10-10 16:44:16.200: W/System.err(381): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:617)
10-10 16:44:16.200: W/System.err(381): at dalvik.system.NativeStart.main(Native Method)
10-10 16:44:16.200: W/System.err(381): Caused by: java.lang.NullPointerException
10-10 16:44:16.200: W/System.err(381): at com.sahadev.activitythemetest.MainActivity4.onCreate(MainActivity4.java:12)
10-10 16:44:16.200: W/System.err(381): at android.app.Activity.performCreate(Activity.java:5231)
10-10 16:44:16.200: W/System.err(381): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
10-10 16:44:16.200: W/System.err(381): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2227)
10-10 16:44:16.200: W/System.err(381): ... 11 more
좋습니다. 이상 정보는 Logcat을 통해 출력됩니다. 다음은 그 내부의 작업 원리를 살펴보겠습니다.
우선:
일반적으로 전역 사용자 정의 이상을 처리할 때 이렇게 쓰는 것을 알고 있습니다.
import java.lang.Thread.UncaughtExceptionHandler;
public class YikaoGlobalCrashHandler implements UncaughtExceptionHandler {
public YikaoGlobalCrashHandler() {
super();
Thread.setDefaultUncaughtExceptionHandler(this);
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
}
}
이러한 방식을 통해 우리는 프로그램이 이상이 발생했을 때 우리의 대상 실례를 리셋한 다음에 우리의 uncaughtException 방법을 호출할 수 있다.
我们知道,如果我们不这么设定,系统是会自己处理异常的,那就一定有一个默认的异常处理对象,没错:
이 방법을 통해 시스템의 기본 UncaughtExceptionHandler 대상을 되돌려줍니다. 이 대상은 어디에서 설정되었을까요?우리는 소스 코드에서 답을 찾았다.Thread.getDefaultUncaughtExceptionHandler();
자바의 가장 기초적인 차원에서 보면
우리 JAVA 입구는:com입니다.android.internal.os.RuntimeInit 클래스의main 방법,main 방법이 어디에서 호출되는지 나중에 다시 토론합시다.public static final void main(String[] argv) { if (argv.length == 2 && argv[1].equals("application")) { if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application"); redirectLogStreams(); } else { if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting tool"); } commonInit(); /* * Now that we're running in interpreted code, call back into native code * to run the system. */ nativeFinishInit(); if (DEBUG) Slog.d(TAG, "Leaving RuntimeInit!"); }
우리가 주목하는 것은 commonInit 방법:private static final void commonInit() { if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!"); /* set default handler; this applies to all threads in the VM */ Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler()); /* * Install a TimezoneGetter subclass for ZoneInfo.db */ TimezoneGetter.setInstance(new TimezoneGetter() { @Override public String getId() { return SystemProperties.get("persist.sys.timezone"); } }); TimeZone.setDefault(null); /* * Sets handler for java.util.logging to use Android log facilities. * The odd "new instance-and-then-throw-away" is a mirror of how * the "java.util.logging.config.class" system property works. We * can't use the system property here since the logger has almost * certainly already been initialized. */ LogManager.getLogManager().reset(); new AndroidConfig(); /* * Sets the default HTTP User-Agent used by HttpURLConnection. */ String userAgent = getDefaultUserAgent(); System.setProperty("http.agent", userAgent); /* * Wire socket tagging to traffic stats. */ NetworkManagementSocketTagger.install(); /* * If we're running in an emulator launched with "-trace", put the * VM into emulator trace profiling mode so that the user can hit * F9/F10 at any time to capture traces. This has performance * consequences, so it's not something you want to do always. */ String trace = SystemProperties.get("ro.kernel.android.tracing"); if (trace.equals("1")) { Slog.i(TAG, "NOTE: emulator trace profiling enabled"); Debug.enableEmulatorTraceOutput(); } initialized = true; }
우리 코드의 두 번째 줄에서 보십시오: Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());그럼 이 UncaughtHandler 클래스는 어디서 정의가 되나요?우리는 런타임 인트에서도java에서 답 찾기:/** * Use this to log a message when a thread exits due to an uncaught * exception. The framework catches these for the main threads, so * this should only matter for threads created by applications. */ private static class UncaughtHandler implements Thread.UncaughtExceptionHandler { public void uncaughtException(Thread t, Throwable e) { try { // Don't re-enter -- avoid infinite loops if crash-reporting crashes. if (mCrashing) return; mCrashing = true; if (mApplicationObject == null) { Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e); } else { StringBuilder message = new StringBuilder(); message.append("FATAL EXCEPTION: ").append(t.getName()).append("
"); final String processName = ActivityThread.currentProcessName(); if (processName != null) { message.append("Process: ").append(processName).append(", "); } message.append("PID: ").append(Process.myPid()); Clog_e(TAG, message.toString(), e); } // Bring up crash dialog, wait for it to be dismissed ActivityManagerNative.getDefault().handleApplicationCrash( mApplicationObject, new ApplicationErrorReport.CrashInfo(e)); } catch (Throwable t2) { try { Clog_e(TAG, "Error reporting crash", t2); } catch (Throwable t3) { // Even Clog_e() fails! Oh well. } } finally { // Try everything to make sure this process goes away. Process.killProcess(Process.myPid()); System.exit(10); } } }
코드에서 StringBuilder의 메시지 대상을 사용하여 기본 정보를 조합한 것을 보고 Cloge 메서드, Cloge 방법 통과
Log.println_native(Log.LOG_ID_CRASH, Log.ERROR, tag,msg + '' + Log.getStackTraceString(tr));Log 로그를 콘솔에 출력합니다.
다음에 호출할 거예요.방법은 다음과 같이 붕괴된 Dialog를 나타냅니다.// Bring up crash dialog, wait for it to be dismissed ActivityManagerNative.getDefault().handleApplicationCrash(mApplicationObject, new ApplicationErrorReport.CrashInfo(e));
결국 프로그램을 죽이고 종료합니다.// Try everything to make sure this process goes away. Process.killProcess(Process.myPid()); System.exit(10);
자, 이것이 바로 시스템이 우리에게 제공한 기본 이상 처리 방법입니다. 다음은 당연히 많은 의문이 있습니다.
1. RuntimeInit 클래스의main 방법은 어디에서 호출되었습니까?
2.throw new NullPointerException();이 부분은 어떻게 집행된 겁니까?
3. Thread의defaultUncaughtHandler 속성은 또 어디에서 호출되었는가.
4.잠깐만
이 방면에 관심이 있는 사람은 평론 구역에서 토론에 참여할 수 있고, 내가 배운 것이 너무 적을 수도 있다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.