215 lines
7.2 KiB
Java
215 lines
7.2 KiB
Java
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.commons.storage.SharedPrefsMgr;
|
|
|
|
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<String, String> info = new HashMap<>();
|
|
private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
|
|
private boolean mDebug = false;
|
|
private final List<CrashCallback> 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<Entry<String, String>> var4 = this.info.entrySet().iterator();
|
|
String result;
|
|
while(var4.hasNext()) {
|
|
Entry<String, String> 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 = SharedPrefsMgr.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();
|
|
}
|
|
}
|
|
|