CrashHandler.java 9.21 KB
package com.hjx.personalcenter.crash;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Environment;
import android.util.Log;

import com.hjx.personalcenter.util.MachineUtil;

import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.HashMap;
import java.util.Map;


/**
 * UncaughtException处理类,当程序发生Uncaught异常的时候,有该类来接管程序,并记录发送错误报告.
 * 
 * @author user
 * 
 */
public class CrashHandler implements UncaughtExceptionHandler {

	public static final String TAG = "CrashHandler";
	// CrashHandler实例
	private static CrashHandler INSTANCE = null;
	// 程序的Context对象
	private Context mContext = null;
	private ExceptionHandler exceptionH = null;
	private StringBuffer log;

	// 文件保存路径
	public static final String LOG_DIR = Environment.getExternalStorageDirectory().toString()+"/hjx/log";;

	private static final String APP_NAME = "APP_NAME";
	private static final String VERSION_NAME = "VERSION_NAME";
	private static final String VERSION_CODE = "VERSION_CODE";
	private static final String APP_MODLE = "APP_MODLE";// 手机型号 
	private static final String CRASH_TIME = "CRASH_TIME";
	private static final String DEVICE_NUMBER = "DEVICE_NUMBER";
	//	private static final String IMSI_CODE = "IMSI_CODE";
	//	private static final String PHONE_NUMBER = "PHONE_NUMBER";
	private static final String OS_VERSION = "OS_VERSION";
	private static final String MAC_ADDRESS = "MAC_ADDRESS";

	/** 保证只有一个CrashHandler实例 */
	private CrashHandler() {
	}

	/** 获取CrashHandler实例 ,单例模式 */
	public static synchronized CrashHandler getInstance() {
		if(INSTANCE == null){
			INSTANCE = new CrashHandler();
		}
		return INSTANCE;
	}

	public interface ExceptionHandler{
		/**
		 * 
		 * @param context
		 * @param ex
		 * @return 如果返回true消费这个throwable false不消费
		 */
		public boolean handleCrash(Context context, Throwable ex);
	}

	public void registerHandler(ExceptionHandler handler){
		this.exceptionH = handler;
	}

	/**
	 * 初始化
	 * 
	 * @param context
	 */
	public void init(Context context) {
		mContext = context;
		log = new StringBuffer();
		// 设置该CrashHandler为程序的默认处理器
		Thread.setDefaultUncaughtExceptionHandler(this);
	}

	/**
	 * 当UncaughtException发生时会转入该函数来处理
	 */
	@Override
	public void uncaughtException(Thread thread, Throwable ex) {
		if (!handleException(ex)) {
			// 收集设备参数信息
			collectDeviceInfo(mContext);

			// 保存日志文件
			saveCrashInfo2File(ex);
			// 解析文件信息
			//parseFile(path);
			// 上传日志文件
			// try {
			// urlPostFile(path);
			// } catch (Exception e) {
			// e.printStackTrace();
			// }
			// 退出程序
		}
		log.setLength(0);
		android.os.Process.killProcess(android.os.Process.myPid());
		System.exit(1);
	}

	/**
	 * 应用程序自己处理未捕获的异常
	 * 
	 * @param ex
	 * @return true: 如果返回true消耗这个throwable false不消耗
	 */
	private boolean handleException(Throwable ex) {
		if (exceptionH == null) {
			return false;
		}else{
			return exceptionH.handleCrash(mContext, ex);
		}
	}

	/**
	 * 收集参数信息
	 * 
	 * @param ctx
	 */
	private void collectDeviceInfo(Context ctx) {

		try {
			PackageManager pm = ctx.getPackageManager();
			PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(),
					PackageManager.GET_META_DATA);
			if (pi != null) {
				String appName = pi.applicationInfo.loadLabel(pm).toString();
				String versionName = pi.versionName == null ? "null"
						: pi.versionName;
				String versionCode = pi.versionCode + "";
				log.append("{\"").append(APP_NAME).append("\":\"")
				.append(appName).append("\",\"")
				.append(VERSION_NAME).append("\":\"")
				.append(versionName).append("\",\"")
				.append(OS_VERSION).append("\":\"")
				.append(Build.VERSION.RELEASE).append("\",\"")
				.append(VERSION_CODE).append("\":\"")
				.append(versionCode).append("\",\"")
				.append(APP_MODLE).append("\":\"")
				.append(Build.MODEL).append("\",\"")
				.append(CRASH_TIME).append("\":\"")
				.append(System.currentTimeMillis()).append("\"");
			}
		} catch (Exception e) {
			Log.e(TAG, "an error occured when collect package info", e);
			log.setLength(0);
			log.append("{\"").append(APP_NAME).append("\":\"")
			.append("unkown").append("\",\"")
			.append(VERSION_NAME).append("\":\"")
			.append("unkown").append("\",\"")
			.append(OS_VERSION).append("\":\"")
			.append(Build.VERSION.RELEASE).append("\",\"")
			.append(VERSION_CODE).append("\":\"")
			.append("unkown").append("\",\"")
			.append(APP_MODLE).append("\":\"")
			.append(Build.MODEL).append("\",\"")
			.append(CRASH_TIME).append("\":\"")
			.append(System.currentTimeMillis()).append("\"");
		}
		try {
			//common android os
			/*
			TelephonyManager mTm = (TelephonyManager)ctx.getSystemService(Context.TELEPHONY_SERVICE);    
			String imei = mTm.getDeviceId();    
			String imsi = mTm.getSubscriberId();    
			String numer = mTm.getLine1Number(); // 手机号码,有的可得,有的不可得    
			if(mTm != null){
				log.append(",\"").append(DEVICE_NUMBER).append("\":\"")
				.append(TextUtils.isEmpty(imei)?"unkown":imei).append("\",\"")
				.append(IMSI_CODE).append("\":\"")
				.append(TextUtils.isEmpty(imsi)?"unkown":imsi).append("\",\"")
				.append(PHONE_NUMBER).append("\":\"")
				.append(TextUtils.isEmpty(numer)?"unkown":numer).append("\"}");
			}
			 */
			//hjx machine

			log.append(",\"").append(DEVICE_NUMBER).append("\":\"")
			.append(getCPUSerial(ctx)).append("\",\"")
			.append(MAC_ADDRESS).append("\":\"")
			.append(getMacAddress(ctx)).append("\"}");

		} catch (Exception e) {
			/*
			 * common android os
			log.append(",\"").append(DEVICE_NUMBER).append("\":\"")
			.append("unkown").append("\",\"")
			.append(IMSI_CODE).append("\":\"")
			.append("unkown").append("\",\"")
			.append(PHONE_NUMBER).append("\":\"")
			.append("unkown").append("\"}");
			 */
			log.append(",\"").append(DEVICE_NUMBER).append("\":\"")
			.append("unkown").append("\",\"")
			.append(MAC_ADDRESS).append("\":\"")
			.append("unkown").append("\"}");
			Log.e(TAG, "an error occured when collect package info", e);
		}
	}

	private String getCPUSerial(Context context) {
		return MachineUtil.getMachineCode(context);
	}

	private String getMacAddress(Context mContext){
		String  ret = null;
		try {
			WifiManager manager = (WifiManager)mContext.getSystemService(Context.WIFI_SERVICE);
			WifiInfo info = manager.getConnectionInfo();
			ret = info.getMacAddress();
		} catch (Exception e) {
			Log.e(TAG, "get wifi address wrong", e);
		}
		return ret;		
	}

	/**
	 * 保存错误信息到文件中
	 * 
	 * @param ex
	 * @return 返回文件名称,便于将文件传送到服务器
	 */
	private String saveCrashInfo2File(Throwable ex) {

		//		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
		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();
		log.append("\n").append(result);
		try {
			//			String name = mContext.getPackageName();
			//			String time = formatter.format(new Date());
			String fileName = System.currentTimeMillis()+".log";
			if (Environment.getExternalStorageState().equals(
					Environment.MEDIA_MOUNTED)) {
				File dir = new File(LOG_DIR);
				if (!dir.exists()) {
					dir.mkdirs();
				}
				FileOutputStream fos = new FileOutputStream(LOG_DIR+"/"
						+ fileName);
				fos.write(log.toString().getBytes());
				fos.close();
			}
			return fileName;
		} catch (Exception e) {
			Log.e(TAG, "an error occured while writing file...", e);
		}
		return null;
	}

	/**
	 * 解析文件信息
	 * 
	 * @param filePath
	 * @return 装有相关信息的map
	 */
	@Deprecated
	public Map<String, String> parseFile(String filePath) {
		BufferedReader read = null;
		try {
			read = new BufferedReader(new FileReader(filePath));
			String line = read.readLine();
			JSONObject jsonObj = new JSONObject(line);
			Map<String, String> map = new HashMap<String, String>();
			map.put(APP_NAME, jsonObj.optString(APP_NAME));
			map.put(APP_MODLE, jsonObj.optString(APP_MODLE));
			map.put(VERSION_NAME, jsonObj.optString(VERSION_NAME));
			map.put(VERSION_CODE, jsonObj.optString(VERSION_CODE));
			map.put(CRASH_TIME, jsonObj.optString(CRASH_TIME));
			StringBuffer sb = new StringBuffer();
			int readed = 0;
			char[] buf = new char[1024];
			while((readed = read.read(buf))!=-1){
				sb.append(buf,0,readed);
			}
			map.put("CONTENT", sb.toString());
			return map;
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			try {
				if(read != null)
					read.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null;
	}
}