您的位置:首页 > 其它

使用CrashHandler来获取应用的oom crash信息

2017-02-21 11:17 477 查看
GitHub源码地址

Android应用开发中不可避免地会发生崩溃,特别是在用户使用过程中,一些特定场景的偶然概率的crash会通常让开发者抓狂。幸运的是Android提供了处理这类问题的方法,当App Crash时,我们可以记录下Crash的原因或者是一些设备信息,并上传到服务器供开发者分析,以便开发者迅速定位问题原因。

实现这个功能我们需要实现
Thread.UncaughtExceptionHandler
这个接口。里面只有一个方法
uncaughtException
。当我们注册一个
UncaughtExceptionHandler
之后,当我们的程序crash时就会回调
uncaughtException
方法,在
uncaughtException
方法中就可以获取到异常信息,我们可以选择把异常信息存储到SD卡中,然后在合适的时机上传到服务器。或者我们还可以在crash发生时,弹出一个对话框告诉用户程序crash了,然后再退出,这样会比闪退温和一些。

下面我们实现了一个捕获OOM的
UncaughtExceptionHandler
的类,发生OOM时可以抓取一些日志,然后可以通过MAT分析生成的hprof文件来定位问题。下面来看一下这个类的用法:

CrashHandler类

public class OomCrashHandler implements Thread.UncaughtExceptionHandler {
final String TAG = "OomCrashHandler";
private Thread.UncaughtExceptionHandler mDefaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
private String mPackageName;
private int mPid;
private StringBuilder mFilename = new StringBuilder(120);
private final String OOM_TARGET_FOLDER = "/crash_log/";
private static final long ONE_DAY_TIME_IN_MILLISECONDS = 24*60*60*1000;
private boolean mDumpingHprof;

OomCrashHandler(String pkgName, int pid) {
this.mPackageName = pkgName;
this.mPid = pid;
this.mDumpingHprof = false;
}

public void uncaughtException(Thread thread, Throwable throwable) {
if(throwable instanceof OutOfMemoryError && !mDumpingHprof) {
Log.w(TAG, "OomCrashHandler capture a oom exception !!!");
if(!dumpHprofData()) {
Log.e(TAG, "Aborting ...");
}else{
//uploadExceptionToServer(); // TODO
}
}

if(mDefaultUncaughtExceptionHandler != null){
mDefaultUncaughtExceptionHandler.uncaughtException(thread, throwable);
} else {
Process.killProcess(Process.myPid());
}
}

//获取目录大小,单位 M
private double getDirSize(File file) {
if(!file.exists()) {
Log.w(TAG, file.toString() + " may not exists !");
return 0.0D;
} else if(!file.isDirectory()) {
double size = (double)file.length() / 1024.0D / 1024.0D;
return size;
} else {
File[] files = file.listFiles();
double size = 0.0D;
int length = files.length;

for(int i = 0; i < length; ++i) {
File f = files[i];
size += this.getDirSize(f);
}

return size;
}
}

//当目录大于1G时且创建时间大于1天时删除旧文件
private void deleteOldFiles(File file) {
if(getDirSize(file) >= 1024.0D) {
Log.w(TAG, "begin to delete old files !");
long currentTimeMillis = System.currentTimeMillis();
File[] listFiles = file.listFiles();

for(int i = 0; i < listFiles.length; ++i) {
if(listFiles[i].isFile()) {
if(currentTimeMillis - listFiles[i].lastModified() > ONE_DAY_TIME_IN_MILLISECONDS) {
listFiles[i].delete();
}
} else if(listFiles[i].isDirectory()) {
deleteOldFiles(listFiles[i]);
}
}

}
}

private boolean getDumpDestinationOfHeap() {
mFilename.delete(0, mFilename.length());
mFilename.append(Environment.getExternalStorageDirectory());
mFilename.append(OOM_TARGET_FOLDER);

File target = new File(mFilename.toString());
if (!target.exists()) {
if (!target.mkdirs()) {
Log.e(TAG, "Creating target hprof directory: \"" + mFilename.toString() + "\" was failed!");
return false;
}
}
deleteOldFiles(target);
mFilename.append(mPackageName);
mFilename.append("_PID:" + mPid);
String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(System.currentTimeMillis()));
mFilename.append("_TIME:"+time);
mFilename.append(".hprof");
target = new File(mFilename.toString().trim());
try {
target.createNewFile();
} catch (IOException e) {
Log.e(TAG, "Creating target hprof file: \"" + mFilename.toString() + "\" was failed! Reason:" + e);

return false;
}

return true;
}

private boolean dumpHprofData() {
if (!getDumpDestinationOfHeap()) {
return false;
}
Log.w(TAG, "Begin to dump hprof to " + mFilename.toString());
long beginDumpTime = SystemClock.uptimeMillis();
try {
mDumpingHprof = true;
Debug.dumpHprofData(mFilename.toString());
} catch (IOException e) {
Log.e(TAG, "Dump hprof to " + mFilename.toString() + " failed ! " + e);
return false;
}
long endDumpTime = (SystemClock.uptimeMillis() - beginDumpTime) / 1000;
Log.w(TAG, "Dump succeed!, Took " + endDumpTime + "s");
return true;
}

public static void registerExceptionHandler(Context context) {
OomCrashHandler handler = new OomCrashHandler(context.getPackageName(), android.os.Process.myPid());
Thread.setDefaultUncaughtExceptionHandler(handler);
}
}


调用

private void createOOM(){
OomCrashHandler.registerExceptionHandler(this);
ArrayList<Bitmap> arrayList = new ArrayList<>();
for(int i = 0; i<100000; i++){
arrayList.add(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: