package com.mogo.launcher.crash; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Build; import android.os.Environment; import android.text.TextUtils; import android.util.Log; import com.mogo.cloud.passport.MoGoAiCloudClientConfig; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.lang.Thread.UncaughtExceptionHandler; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; public class CrashSystem implements UncaughtExceptionHandler { public static final String TAG = "CrashSystem"; private String mAppPackage = null; private String mAppVersionCode = null; private String mAppVersionName = null; private String mAppName = null; private String mOsVersion = null; private String mDeviceId = null; private UncaughtExceptionHandler mDefaultHandler; private final Map info = new HashMap<>(); private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss"); private boolean mDebug = false; private final List callbackList = new ArrayList<>(); private static CrashSystem sCrashSystem = null; private static final Object lock = new Object(); public void init() { this.mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); Thread.setDefaultUncaughtExceptionHandler(this); } /** * 是否收集记录crash信息 * @param debug 是否是debug */ public void setDebug(boolean debug) { this.mDebug = debug; } /** * 添加crash事件回调 */ public void addCallback(CrashCallback callback) { if(callback != null) { callbackList.add(callback); } } private CrashSystem(Context context) { this.inflateSystemInfo(context); } public static CrashSystem getInstance(Context context) { CrashSystem crashSystem = sCrashSystem; if(crashSystem == null) { synchronized (lock) { crashSystem = sCrashSystem; if(crashSystem == null) { crashSystem = new CrashSystem(context.getApplicationContext()); sCrashSystem = crashSystem; } } } return crashSystem; } @Override public void uncaughtException(Thread thread, Throwable ex) { try { this.handleException(ex); dispatchCrashError(); } finally { if (mDefaultHandler != null) { mDefaultHandler.uncaughtException(thread, ex); } } } /** * 分发异常事件 */ private void dispatchCrashError() { for (CrashCallback callback : callbackList) { if(callback != null) { callback.onCrashError(); } } } private boolean handleException(Throwable ex) { if (ex != null) { String msg = ex.getLocalizedMessage(); Log.e("CrashSystem", msg); String filePath = saveCrashInfo2File(ex); Log.i(TAG, "handleException: filePath = " + filePath); } return true; } private String saveCrashInfo2File(Throwable ex) { try { if(!Environment.getExternalStorageState().equals("mounted")) { return null; } File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "crash"); if(!dir.exists()) { dir.mkdir(); } String[] fileList = dir.list((dir1, name) -> name.contains(mAppPackage)); if(fileList == null || fileList.length >= 20) { //避免crash日志一直重复 return null; } String time = this.format.format(new Date()); String fileName = "app-crash-" + this.mAppPackage + "-" + time + ".log"; if(mDebug) { fileName = "debug-" + fileName; } String fileTemp = fileName + ".temp"; StringBuilder sb = new StringBuilder(); Iterator> var4 = this.info.entrySet().iterator(); String result; while(var4.hasNext()) { Entry entry = var4.next(); String key = entry.getKey(); result = entry.getValue(); sb.append(key).append("=").append(result).append("\n"); } sb.append("TIME=").append(System.currentTimeMillis()).append("\n"); sb.append("fileName=").append(fileName).append("\n"); Writer writer = new StringWriter(); PrintWriter pw = new PrintWriter(writer); ex.printStackTrace(pw); for(Throwable cause = ex.getCause(); cause != null; cause = cause.getCause()) { cause.printStackTrace(pw); } pw.close(); result = writer.toString(); sb.append(result); FileOutputStream fos = null; try { File dest = new File(dir, fileTemp); fos = new FileOutputStream(dest); fos.write(sb.toString().getBytes()); fos.flush(); File file = new File(dir,fileName); dest.renameTo(file); return dir.getAbsolutePath() + File.separator + fileName; } catch (IOException var13) { var13.printStackTrace(); } finally { try { if (fos != null) { fos.close(); } } catch (IOException ignore) {} } } catch (Throwable ignore) { } return null; } private void inflateSystemInfo(Context context) { this.mAppPackage = context.getPackageName(); PackageManager pm = context.getPackageManager(); try { PackageInfo packageInfo = pm.getPackageInfo(this.mAppPackage, 0); this.mAppVersionCode = String.valueOf(packageInfo.versionCode); this.mAppVersionName = packageInfo.versionName; this.mAppPackage = packageInfo.packageName; this.mAppName = packageInfo.applicationInfo.loadLabel(context.getPackageManager()).toString(); this.mOsVersion = Build.DISPLAY; String deviceId = MoGoAiCloudClientConfig.getInstance().getSn(); if(TextUtils.isEmpty(deviceId)) { deviceId = "11111111"; } this.mDeviceId = deviceId; } catch (Exception var5) { var5.printStackTrace(); } this.info.put("appName",this.mAppName); this.info.put("appPackageName", this.mAppPackage); this.info.put("versionCode", this.mAppVersionCode); this.info.put("versionName", this.mAppVersionName); this.info.put("sn", this.mDeviceId); this.info.put("DISPLAY", this.mOsVersion); } public interface CrashCallback { void onCrashError(); } }