Android Framework上传crash和anr log

java层crash通知

当一个进程在通过zygote创建时就会调用 zygoteInit--> 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);
        ...
    }

然后设置UncaughtHandler监视进程不能捕获的Exception,然后先通知AMS,再调用killProcess干掉自己


/**
     * 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);
                }

                // Try to end profiling. If a profiler is running at this point, and we kill the
                // process (below), the in-memory buffer will be lost. So try to stop, which will
                // flush the buffer. (This makes method trace profiling useful to debug crashes.)
                if (ActivityThread.currentActivityThread() != null) {
                    ActivityThread.currentActivityThread().stopProfiling();
                }

                // Bring up crash dialog, wait for it to be dismissed
                ActivityManagerNative.getDefault().handleApplicationCrash(
                        mApplicationObject, new ApplicationErrorReport.CrashInfo(e));
            } catch (Throwable t2) {
                if (t2 instanceof DeadObjectException) {
                    // System process is dead; ignore
                } else {
                    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);
            }
        }
    }

ANR引起的原因有以下几种

  • BroadcastQueue

  • Service超时

  • Input 事件分发无响应

  • provider无响应

ActivityManagerService中处理error信息,并保存crash日志

java层的Crash,ANR最终都会到addErrorToDropBox处理

  • anr/crash

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.



        UploadErrorMessage uploadError = UploadErrorMessage.getInstance(mContext);

        uploadError.noteProcessError(eventType, process, processName,

                activity, parent, subject, report, logFile, crashInfo);

}

上传信息代码


package com.android.server.am;



import android.app.ApplicationErrorReport;

import android.content.Context;

import android.util.Slog;



import java.io.File;



import org.json.JSONStringer;

import org.json.JSONObject;

import org.json.JSONException;



import com.putao.minisdk.MiniCollectionSdk;



/**

 * upload message log to server when app chash or anr

 * Created by putao on 17-8-2.

 */

class UploadErrorMessage {

    private static final String TAG = "UploadErrorMessage";

    private static final boolean DEBUG = true;

    private final Context mContext;

    private static UploadErrorMessage mInstance = null;



    // sdk for use upload data to server

    private MiniCollectionSdk minisdk = null;



    public static UploadErrorMessage getInstance(Context context) {

        if (mInstance == null) {

            synchronized (UploadErrorMessage.class) {

                if (mInstance == null) {

                    mInstance = new UploadErrorMessage(context);

                }

            }

        }



        return mInstance;

    }



    private UploadErrorMessage(Context context) {

        mContext = context;



        // config minisdk appid logtype ...

        if (minisdk == null) {

            minisdk = MiniCollectionSdk.getInstance(context);

        }

        minisdk.setOnBindChangedListener(new MiniCollectionSdk.OnBindChangedListener() {

            public void onBindSuccess() {

                Slog.d(TAG, "onBindSuccess...");

                minisdk.setDataInfo("Paios", "23", "custom");

                minisdk.didFinishLaunched("85bfac7251c93e16b7b946ea5eded05d",

                        "164594b08b39e5f74a891699da8aff62");

            }

        });

        minisdk.bindService();  // 绑定后台service.

    }



    /**

     * Notice a description of an error (crash, WTF, ANR) to the server.

     * @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 noteProcessError(String eventType, final ProcessRecord process,

            final String processName, final ActivityRecord activity,

            final ActivityRecord parent, final String subject,

            final String report, final File logFile,

            final ApplicationErrorReport.CrashInfo crashInfo) {



        if (eventType != null && eventType.equals("anr")) {

            new Thread(new Runnable() {

                @Override

                public void run() {

                    noteProcessAnr(processName, subject, report, activity.shortComponentName);

                }

            }).start();

        }



        if (eventType != null && eventType.equals("crash")) {

            new Thread(new Runnable() {

                @Override

                public void run() {

                    noteProcessCrash(processName, crashInfo);

                }

            }).start();

        }

    }



    /**

     * Notice that the server this app is crash

     *

     * @param processName process name of crash

     * @param crashInfo Contains all the crash information

     *

     * eg.

     * upload crash json format is as follows

     * {

     * "processName":"com.autonavi.minimap",

     * "type":"crashlog",

     * "appVersion":1.6.1,

     * "timestamp":1500617925676,

     * "errorType":"crash",

     * "exceptionClassName":"java.lang.NullPointerException",

     * "exceptionMessage":"Attempt to ... on a null object reference",

     * "throwFileName":"MainActivity.java",

     * "throwClassName":"com.example.putao.crashanrapp.MainActivity",

     * "throwMethodName":"CreateCrash",

     * "stackTrace":"...",

     * "throwLineNumber":"56",

     * }

     */

    private void noteProcessCrash(String processName,

            ApplicationErrorReport.CrashInfo crashInfo) {

        JSONStringer json = new JSONStringer();

        try {

            json.object();

            json.key("processName").value(processName);

            json.key("type").value("crashlog");

            json.key("appVersion").value("unknow");

            json.key("timestamp").value(System.currentTimeMillis());

            json.key("errorType").value("crash");

            json.key("exceptionClassName").value(crashInfo.exceptionClassName);

            // Can not contain single quotation marks

            json.key("exceptionMessage").value(crashInfo.exceptionMessage.replace('\'', ' '));

            json.key("throwFileName").value(crashInfo.throwFileName);

            json.key("throwClassName").value(crashInfo.throwClassName);

            json.key("throwMethodName").value(crashInfo.throwMethodName);

            json.key("stackTrace").value(crashInfo.stackTrace.replace('\'', ' '));

            json.key("throwLineNumber").value(crashInfo.throwLineNumber);

            json.endObject();

        } catch (JSONException e) {

            e.printStackTrace();

        }



        // upload crash log to server

        minisdk.addUnlimitedInfo(json.toString(), "custom");

    }



    /**

     * Notice that the server this app is anr

     *

     * @param processName process name of crash

     * @param cause the anr reason

     * @param info anr information, contains cpu infomation

     * @param activity anr of activity

     *

     * eg.

     * upload anr json format is as follows

     * {

     * "processName":"com.autonavi.minimap",

     * "type":"anrlog",

     * "appVersion":1.6.1,

     * "timestamp":1500617925676,

     * "errorType":"anr",

     * "activity":"com.example.putao.crashanrapp/.MainActivity",

     * "cause":"Input dispatching timed out (Waiting to send non-key ... ",

     * "info":"ANR in com.example.putao.crashanrapp ... ",

     * }

     */

    private void noteProcessAnr(String processName, String cause,

            String info, String activity) {

        JSONStringer json = new JSONStringer();

        try {

            json.object();

            json.key("processName").value(processName);

            json.key("type").value("anrlog");

            json.key("appVersion").value("unknow");

            json.key("timestamp").value(System.currentTimeMillis());

            json.key("errorType").value("anr");

            json.key("activity").value(activity);

            json.key("cause").value(cause);

            json.key("info").value(info);

            json.endObject();

        } catch (JSONException e) {

            e.printStackTrace();

        }



        // upload anr log to server

        minisdk.addUnlimitedInfo(json.toString(), "custom");

    }

}

你可能感兴趣的:(Android Framework上传crash和anr log)