package com.tool.common.log.crash; import android.os.Build; import android.os.Environment; import com.tool.common.log.QLog; import com.tool.common.log.log.LogConfig; import com.tool.common.log.util.AppUtils; import com.tool.common.log.util.FileUtil; import com.tool.common.log.util.TimeUtils; import java.io.FileOutputStream; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; public class ThreadCatchInterceptor { // Thread.UncaughtException private Thread.UncaughtExceptionHandler defaultExceptionHandler; // Crash Stack-related information private List<String> crashInfo = new ArrayList<>(); // Log Config private LogConfig logConfig = null; // Crash Save Directory private String PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/QLog/" + "CrashLog/"; private final Logger logger; public ThreadCatchInterceptor() { this.logger = Logger.DEFAULT; logConfig = LogConfig.getConfig(); } private static class CrashHolder { private static ThreadCatchInterceptor crash = new ThreadCatchInterceptor(); } /** * Get Singleton * * @return Setting */ public static ThreadCatchInterceptor getInstance() { return CrashHolder.crash; } /** * Install */ public void install(final CallBack callBack) { if (!FileUtil.existSDCard()) { logger.log("Not installed SDCard, which causes the crash information could not be saved."); } else { if (!FileUtil.createDirectory(PATH)) { logger.log("Create QLog directory fails, which causes the crash information could not be saved."); } } defaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); if (defaultExceptionHandler != null) { Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread thread, Throwable throwable) { if (callBack != null) { callBack.error(throwable); } if (handleException(throwable)) { // Save the error report to a file callBack.finish(save(throwable)); } else { logger.log("Collected error information failed."); } if (defaultExceptionHandler != null) { defaultExceptionHandler.uncaughtException(thread, throwable); } } }); } else { logger.log("Get DefaultUncaughtExceptionHandler Failure."); } } /** * Gathering error messages * * @param throwable * @return */ private boolean handleException(Throwable throwable) { if (throwable == null) { return false; } if (logConfig.getContext() != null) { crashInfo.add("Version:" + AppUtils.getVersionName(logConfig.getContext())); } Field[] fields = Build.class.getDeclaredFields(); for (Field field : fields) { try { field.setAccessible(true); crashInfo.add(field.getName() + ": " + field.get(null)); } catch (Exception e) { e.printStackTrace(); } } return true; } /** * Save the error message to a file * * @param throwable * @return */ private String save(Throwable throwable) { Writer writer = new StringWriter(); PrintWriter printWriter = new PrintWriter(writer); throwable.printStackTrace(printWriter); Throwable cause = throwable.getCause(); while (cause != null) { cause.printStackTrace(printWriter); cause = cause.getCause(); } String result = writer.toString(); printWriter.close(); crashInfo.add(result); String savePath = PATH + TimeUtils.formatTime() + "_" + TimeUtils.currentTimeMillis() + ".log"; try { FileOutputStream trace = new FileOutputStream(savePath, true); for (String string : crashInfo) { trace.write((string + "\n").getBytes()); } trace.flush(); trace.close(); } catch (Exception e) { e.printStackTrace(); } return savePath; } public void uninstall() { Thread.setDefaultUncaughtExceptionHandler(null); } public interface CallBack { /** * Fires an exception * * @param throwable */ void error(Throwable throwable); /** * Save finished * * @param path */ void finish(String path); } private interface Logger { void log(String message); Logger DEFAULT = new Logger() { @Override public void log(String message) { QLog.w(message); } }; } }