java application的异常处理流程

来源:互联网 发布:软件壳 编辑:程序博客网 时间:2024/05/22 02:20
1. java application 异常发生后的代码流程:
代码流程是函数文件
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java的函数UncaughtHandler控制的:
    /**
     * 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 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);
            }
        }
    }


2. application crash后输出什么样的log:
message.append("FATAL EXCEPTION: ").append(t.getName()).append("\n");
message.append("Process: ").append(processName).append(", ");
message.append("PID: ").append(Process.myPid());
5395  5395 E AndroidRuntime: FATAL EXCEPTION: main
5395  5395 E AndroidRuntime: Process: com.example.ritter.fcandanr, PID: 5395


下面的调用栈是哪里输出的?
    private static int Clog_e(String tag, String msg, Throwable tr) {
        return Log.println_native(Log.LOG_ID_CRASH, Log.ERROR, tag,
                msg + '\n' + Log.getStackTraceString(tr));
    }
函数Clog_e中调用了getStackTraceString
5395  5395 E AndroidRuntime: java.lang.IllegalStateException: Could not execute method for android:onClick
5395  5395 E AndroidRuntime: at android.view.View$DeclaredOnClickListener.onClick(View.java:4461)
5395  5395 E AndroidRuntime: at android.view.View.performClick(View.java:5207)
5395  5395 E AndroidRuntime: at android.view.View$PerformClick.run(View.java:21177)
5395  5395 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:739)
5395  5395 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:95)
5395  5395 E AndroidRuntime: at android.os.Looper.loop(Looper.java:148)
5395  5395 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5485)
5395  5395 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
5395  5395 E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:738)
5395  5395 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628)
5395  5395 E AndroidRuntime: Caused by: java.lang.reflect.InvocationTargetException
5395  5395 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
5395  5395 E AndroidRuntime: at android.view.View$DeclaredOnClickListener.onClick(View.java:4456)
5395  5395 E AndroidRuntime: ... 9 more
5395  5395 E AndroidRuntime: Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String  java.lang.String.toString()' on a null object reference
E AndroidRuntime: at com.example.ritter.fcandanr.MainActivity.onClickFC(MainActivity.java:75)
5395  5395 E AndroidRuntime: ... 11 more


3. 除了输出异常log外:还调用了:handleApplicationCrash
    /**
     * Used by {@link com.android.internal.os.RuntimeInit} to report when an application crashes.
     * The application process will exit immediately after this call returns.
     * @param app object of the crashing app, null for the system server
     * @param crashInfo describing the exception
     */
    public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
        ProcessRecord r = findAppProcess(app, "Crash");
        final String processName = app == null ? "system_server"
                : (r == null ? "unknown" : r.processName);


        handleApplicationCrashInner("crash", r, processName, crashInfo);
    }


    /* Native crash reporting uses this inner version because it needs to be somewhat
     * decoupled from the AM-managed cleanup lifecycle
     */
    void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
            ApplicationErrorReport.CrashInfo crashInfo) {
        EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
                UserHandle.getUserId(Binder.getCallingUid()), processName,
                r == null ? -1 : r.info.flags,
                crashInfo.exceptionClassName,
                crashInfo.exceptionMessage,
                crashInfo.throwFileName,
                crashInfo.throwLineNumber);


        addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);


        crashApplication(r, crashInfo);
    }


3.1 event log: AM_CRASH的输出:
        EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
                UserHandle.getUserId(Binder.getCallingUid()), processName,
                r == null ? -1 : r.info.flags,
                crashInfo.exceptionClassName,
                crashInfo.exceptionMessage,
                crashInfo.throwFileName,
                crashInfo.throwLineNumber);


am_crash: [5395,0,com.example.ritter.fcandanr,948485702,java.lang.NullPointerException,Attempt to invoke virtual method 'java.lang.String java.lang.String.toString()' on a null object reference,MainActivity.java,75]


am_crash: [
5395,
0,
com.example.ritter.fcandanr,
948485702,
java.lang.NullPointerException,
Attempt to invoke virtual method 'java.lang.String java.lang.String.toString()' on a null object reference,
MainActivity.java,
75]


4 addErrorToDropBox
调用dropbox服务保存一些信息到dropbox路径
    /**
     * Write a description of an error (crash, WTF, ANR) to the drop box.
     * @param eventType to include in the drop box tag ("crash", "wtf", etc.)
     * @param process which caused the error, null means the system server
     * @param activity which triggered the error, null if unknown
     * @param parent activity related to the error, null if unknown
     * @param subject line related to the error, null if absent
     * @param report in long form describing the error, null if absent
     * @param logFile to include in the report, null if none
     * @param crashInfo giving an application stack trace, null if absent
     */
    public void addErrorToDropBox(String eventType,
            ProcessRecord process, String processName, ActivityRecord activity,
            ActivityRecord parent, String subject,
            final String report, final File logFile,
            final ApplicationErrorReport.CrashInfo crashInfo) {
        // NOTE -- this must never acquire the ActivityManagerService lock,
        // otherwise the watchdog may be prevented from resetting the system.


        final String dropboxTag = processClass(process) + "_" + eventType;
        final DropBoxManager dbox = (DropBoxManager)
                mContext.getSystemService(Context.DROPBOX_SERVICE);


        // Exit early if the dropbox isn't configured to accept this report type.
        if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return;


        final StringBuilder sb = new StringBuilder(1024);
        appendDropBoxProcessHeaders(process, processName, sb);
        if (activity != null) {
            sb.append("Activity: ").append(activity.shortComponentName).append("\n");
        }
        if (parent != null && parent.app != null && parent.app.pid != process.pid) {
            sb.append("Parent-Process: ").append(parent.app.processName).append("\n");
        }
        if (parent != null && parent != activity) {
            sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n");
        }
        if (subject != null) {
            sb.append("Subject: ").append(subject).append("\n");
        }
        sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
        if (Debug.isDebuggerConnected()) {
            sb.append("Debugger: Connected\n");
        }
        sb.append("\n");


        // Do the rest in a worker thread to avoid blocking the caller on I/O
        // (After this point, we shouldn't access AMS internal data structures.)
        Thread worker = new Thread("Error dump: " + dropboxTag) {
            @Override
            public void run() {
                if (report != null) {
                    sb.append(report);
                }
                if (logFile != null) {
                    try {
                        sb.append(FileUtils.readTextFile(logFile, DROPBOX_MAX_SIZE,
                                    "\n\n[[TRUNCATED]]"));
                    } catch (IOException e) {
                        Slog.e(TAG, "Error reading " + logFile, e);
                    }
                }
                if (crashInfo != null && crashInfo.stackTrace != null) {
                    sb.append(crashInfo.stackTrace);
                }


                String setting = Settings.Global.ERROR_LOGCAT_PREFIX + dropboxTag;
                int lines = Settings.Global.getInt(mContext.getContentResolver(), setting, 0);
                if (lines > 0) {
                    sb.append("\n");


                    // Merge several logcat streams, and take the last N lines
                    InputStreamReader input = null;
                    try {
                        java.lang.Process logcat = new ProcessBuilder("/system/bin/logcat",
                                "-v", "time", "-b", "events", "-b", "system", "-b", "main",
                                "-b", "crash",
                                "-t", String.valueOf(lines)).redirectErrorStream(true).start();


                        try { logcat.getOutputStream().close(); } catch (IOException e) {}
                        try { logcat.getErrorStream().close(); } catch (IOException e) {}
                        input = new InputStreamReader(logcat.getInputStream());


                        int num;
                        char[] buf = new char[8192];
                        while ((num = input.read(buf)) > 0) sb.append(buf, 0, num);
                    } catch (IOException e) {
                        Slog.e(TAG, "Error running logcat", e);
                    } finally {
                        if (input != null) try { input.close(); } catch (IOException e) {}
                    }
                }


                dbox.addText(dropboxTag, sb.toString());
            }
        };


        if (process == null) {
            // If process is null, we are being called from some internal code
            // and may be about to die -- run this synchronously.
            worker.run();
        } else {
            worker.start();
        }
    }


4.1 dropbox中保存什么样的文件名
当前的文件名是data_app_crash@1482833732852.txt
dropbox中的文件名由dropboxTag决定:
dropboxTag = processClass(process):
    private static String processClass(ProcessRecord process) {
        if (process == null || process.pid == MY_PID) {
            return "system_server";
        } else if ((process.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
            return "system_app";
        } else {
            return "data_app";
        }
    }


4.2 dropbox中保存的文件内容是:
rocess: com.example.ritter.fcandanr
Flags: 0x38a8be46
Package: com.example.ritter.fcandanr v1 (1.0)
Build: Xiaomi/gemini/gemini:6.0.1/MXB48T/1.1.1:user/test-keys


java.lang.IllegalStateException: Could not execute method for android:onClick
at android.view.View$DeclaredOnClickListener.onClick(View.java:4461)
at android.view.View.performClick(View.java:5207)
at android.view.View$PerformClick.run(View.java:21177)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5485)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:738)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at android.view.View$DeclaredOnClickListener.onClick(View.java:4456)
... 9 more
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.String.toString()' on a null object reference
at com.example.ritter.fcandanr.MainActivity.onClickFC(MainActivity.java:75)
... 11 more


4.3 dropbox中也是可以保存当前的logcat
但是受setting控制:
String setting = Settings.Global.ERROR_LOGCAT_PREFIX + dropboxTag;
int lines = Settings.Global.getInt(mContext.getContentResolver(), setting, 0);


5. 弹出的对话框crashApplication(r, crashInfo); 
    /**
     * Bring up the "unexpected error" dialog box for a crashing app.
     * Deal with edge cases (intercepts from instrumented applications,
     * ActivityController, error intent receivers, that sort of thing).
     * @param r the application crashing
     * @param crashInfo describing the failure
     */
    private void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
            Message msg = Message.obtain();
            msg.what = SHOW_ERROR_MSG;
            HashMap data = new HashMap();
            data.put("result", result);
            data.put("app", r);


            // MIUI ADD:
            data.put("crash", crashInfo);


            msg.obj = data;
            mUiHandler.sendMessage(msg);


            Binder.restoreCallingIdentity(origId);
    }


6. system_server的异常也是按上面的流程处理的
system_server的异常也是会弹出界面?会导致framework 层重启?
0 0