From 835591e5dc4d900eecddb185ab412f0c2878309c Mon Sep 17 00:00:00 2001 From: pppscn <35696959@qq.com> Date: Sun, 23 Jan 2022 13:33:56 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=EF=BC=9A=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E6=8D=95=E8=8E=B7=E7=B1=BB=EF=BC=8C=E8=AE=B0=E5=BD=95crash?= =?UTF-8?q?=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../idormy/sms/forwarder/CrashHandler.java | 185 ++++++++++++++++++ .../idormy/sms/forwarder/MyApplication.java | 4 + 2 files changed, 189 insertions(+) create mode 100644 app/src/main/java/com/idormy/sms/forwarder/CrashHandler.java diff --git a/app/src/main/java/com/idormy/sms/forwarder/CrashHandler.java b/app/src/main/java/com/idormy/sms/forwarder/CrashHandler.java new file mode 100644 index 00000000..11a1d60e --- /dev/null +++ b/app/src/main/java/com/idormy/sms/forwarder/CrashHandler.java @@ -0,0 +1,185 @@ +package com.idormy.sms.forwarder; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Looper; +import android.util.Log; +import android.widget.Toast; + +import androidx.annotation.NonNull; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.Thread.UncaughtExceptionHandler; +import java.lang.reflect.Field; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +/** + * UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告 + */ +public class CrashHandler implements UncaughtExceptionHandler { + public static final String TAG = "CrashHandler"; + //系统默认的UncaughtException处理类 + private Thread.UncaughtExceptionHandler mDefaultHandler; + //CrashHandler实例 + @SuppressLint("StaticFieldLeak") + private static final CrashHandler INSTANCE = new CrashHandler(); + //程序的Context对象 + private Context mContext; + //用来存储设备信息和异常信息 + private final Map infos = new HashMap<>(); + //用于格式化日期,作为日志文件名的一部分 + @SuppressLint("SimpleDateFormat") + private final DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); + + /** + * 保证只有一个CrashHandler实例 + */ + private CrashHandler() { + } + + /** + * 获取CrashHandler实例 ,单例模式 + */ + public static CrashHandler getInstance() { + return INSTANCE; + } + + /** + * 初始化 + */ + public void init(Context context) { + mContext = context; + //获取系统默认的UncaughtException处理器 + mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); + //设置该CrashHandler为程序的默认处理器 + Thread.setDefaultUncaughtExceptionHandler(this); + } + + /** + * 当UncaughtException发生时会转入该函数来处理 + */ + @Override + public void uncaughtException(@NonNull Thread thread, @NonNull Throwable ex) { + if (!handleException(ex) && mDefaultHandler != null) { + //如果用户没有处理则让系统默认的异常处理器来处理 + mDefaultHandler.uncaughtException(thread, ex); + } else { + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + Log.e(TAG, "error : ", e); + } //退出程序 + android.os.Process.killProcess(android.os.Process.myPid()); + System.exit(1); + } + } + + /** + * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成 + * + * @param ex + * @return true:如果处理了该异常信息;否则返回false. + */ + private boolean handleException(Throwable ex) { + if (ex == null) { + return false; + } //使用Toast来显示异常信息 + new Thread() { + @Override + public void run() { + Looper.prepare(); + Toast.makeText(mContext, "很抱歉,程序出现异常,即将退出.", Toast.LENGTH_LONG).show(); + Looper.loop(); + } + }.start(); + //收集设备参数信息 + collectDeviceInfo(mContext); + //保存日志文件 + saveCrashInfo2File(ex); + return true; + } + + /** + * 收集设备参数信息 + */ + public void collectDeviceInfo(Context ctx) { + try { + PackageManager pm = ctx.getPackageManager(); + PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES); + if (pi != null) { + String versionName = pi.versionName == null ? "null" : pi.versionName; + String versionCode = pi.versionCode + ""; + infos.put("versionName", versionName); + infos.put("versionCode", versionCode); + } + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "an error occured when collect package info", e); + } + Field[] fields = Build.class.getDeclaredFields(); + for (Field field : fields) { + try { + field.setAccessible(true); + infos.put(field.getName(), Objects.requireNonNull(field.get(null)).toString()); + Log.d(TAG, field.getName() + " : " + field.get(null)); + } catch (Exception e) { + Log.e(TAG, "an error occured when collect crash info", e); + } + } + } + + /** + * 保存错误信息到文件中 + */ + @SuppressWarnings({"ResultOfMethodCallIgnored", "UnusedReturnValue"}) + private String saveCrashInfo2File(Throwable ex) { + StringBuilder sb = new StringBuilder(); + for (Map.Entry entry : infos.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + sb.append(key).append("=").append(value).append("\n"); + } + Writer writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + ex.printStackTrace(printWriter); + Throwable cause = ex.getCause(); + while (cause != null) { + cause.printStackTrace(printWriter); + cause = cause.getCause(); + } + printWriter.close(); + String result = writer.toString(); + sb.append(result); + try { + long timestamp = System.currentTimeMillis(); + String time = formatter.format(new Date()); + String fileName = "crash-" + time + "-" + timestamp + ".log"; + + String path = mContext.getCacheDir().getPath() + File.separator + "crash" + File.separator; + Log.e(TAG, path); + File dir = new File(path); + if (!dir.exists()) { + dir.mkdirs(); + } + FileOutputStream fos = new FileOutputStream(path + fileName); + fos.write(sb.toString().getBytes()); + fos.close(); + + return fileName; + } catch (Exception e) { + Log.e(TAG, "an error occured while writing file...", e); + } + return null; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/idormy/sms/forwarder/MyApplication.java b/app/src/main/java/com/idormy/sms/forwarder/MyApplication.java index d2b1da69..9a2d5c8c 100644 --- a/app/src/main/java/com/idormy/sms/forwarder/MyApplication.java +++ b/app/src/main/java/com/idormy/sms/forwarder/MyApplication.java @@ -44,6 +44,10 @@ public class MyApplication extends Application { super.onCreate(); context = getApplicationContext(); + //异常捕获类 + CrashHandler crashHandler = CrashHandler.getInstance(); + crashHandler.init(getApplicationContext()); + try { //前台服务 Intent intent = new Intent(this, FrontService.class);