日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

从源码角度分析Android系统的异常捕获机制是如何运行的

發(fā)布時(shí)間:2024/7/5 Android 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从源码角度分析Android系统的异常捕获机制是如何运行的 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

我們?cè)陂_發(fā)的時(shí)候經(jīng)常會(huì)遇到各種異常,當(dāng)程序遇到異常,便會(huì)將異常信息拋到LogCat中,那這個(gè)過程是怎么實(shí)現(xiàn)的呢?


我們以一個(gè)例子開始:

import android.app.Activity; import android.os.Bundle;public class MainActivity4 extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);throw new NullPointerException();} }
這個(gè)程序一啟動(dòng)便會(huì)拋一個(gè)異常到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
好,異常信息就會(huì)通過Logcat輸出出來,接下來我們一起看一下它內(nèi)部的工作原理:

首先:

我們知道通常我們?cè)谔幚砣肿远x異常的時(shí)候通常會(huì)這么寫:

import java.lang.Thread.UncaughtExceptionHandler;public class YikaoGlobalCrashHandler implements UncaughtExceptionHandler {public YikaoGlobalCrashHandler() {super();Thread.setDefaultUncaughtExceptionHandler(this);}@Overridepublic void uncaughtException(Thread thread, Throwable ex) {} } 通過這樣的方式,我們便可以使程序在遇到異常的時(shí)候回調(diào)我們的對(duì)象實(shí)例,然后調(diào)用我們的uncaughtException方法。

我們知道,如果我們不這么設(shè)定,系統(tǒng)是會(huì)自己處理異常的,那就一定有一個(gè)默認(rèn)的異常處理對(duì)象,沒錯(cuò):

Thread.getDefaultUncaughtExceptionHandler();通過這個(gè)方法會(huì)返回一個(gè)系統(tǒng)默認(rèn)的UncaughtExceptionHandler對(duì)象,那么這個(gè)對(duì)象是在哪被設(shè)置進(jìn)去的呢?我們從源代碼里面找答案:

咱們從Java最基礎(chǔ)層面看起,

我們的JAVA入口是:com.android.internal.os.RuntimeInit類的main方法,至于main方法在哪被調(diào)用,我們以后再討論:

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!");}
我們關(guān)注的是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() {@Overridepublic 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());那這個(gè)UncaughtHandler類在哪被定義呢?我們還可以在RuntimeInit.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("\n");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 dismissedActivityManagerNative.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的message對(duì)象對(duì)基本信息進(jìn)行了組合,然后調(diào)用Clog_e方法,Clog_e方法通過

Log.println_native(Log.LOG_ID_CRASH, Log.ERROR, tag,msg + '\n' + Log.getStackTraceString(tr));將Log日志輸出到控制臺(tái)。

接下來會(huì)調(diào)用

// Bring up crash dialog, wait for it to be dismissedActivityManagerNative.getDefault().handleApplicationCrash(mApplicationObject, new ApplicationErrorReport.CrashInfo(e));方法將我們的崩潰的Dialog顯示出來,就像這樣:

最終它還會(huì)將我們的程序殺死退出:

// Try everything to make sure this process goes away.Process.killProcess(Process.myPid());System.exit(10);
好這就是系統(tǒng)為我們提供的默認(rèn)異常處理方法,接下來當(dāng)然還有不少疑問:

1.RuntimeInit類的main方法是在哪被調(diào)用的。

2.throw new NullPointerException();這部分是怎么執(zhí)行的。

3.Thread的defaultUncaughtHandler屬性又是在哪被調(diào)用的。

4.等等


歡迎對(duì)這方面有興趣的可以在評(píng)論區(qū)參與討論,也有可能是我學(xué)的還太少。

總結(jié)

以上是生活随笔為你收集整理的从源码角度分析Android系统的异常捕获机制是如何运行的的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。