CrashHandler.java 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. package com.guangzhou.haochuan.jxtv.util;
  2. import android.content.Context;
  3. import android.content.pm.PackageInfo;
  4. import android.content.pm.PackageManager;
  5. import android.os.Build;
  6. import android.os.Looper;
  7. import android.util.Log;
  8. import com.guangzhou.haochuan.jxtv.viewModel.ErrorDataViewModel;
  9. import com.ystgame.sdk.billing.api.GameInterface;
  10. import java.io.BufferedReader;
  11. import java.io.FileOutputStream;
  12. import java.io.FileReader;
  13. import java.io.PrintWriter;
  14. import java.io.StringWriter;
  15. import java.io.Writer;
  16. import java.lang.reflect.Field;
  17. import java.text.DateFormat;
  18. import java.text.SimpleDateFormat;
  19. import java.util.Date;
  20. import java.util.HashMap;
  21. import java.util.Map;
  22. /**
  23. * Created by yunhaipiaodi on 2017/10/24.
  24. */
  25. public class CrashHandler implements Thread.UncaughtExceptionHandler {
  26. public static final String TAG = "CrashHandler";
  27. //系统默认的UncaughtException处理类
  28. private Thread.UncaughtExceptionHandler mDefaultHandler;
  29. //CrashHandler实例
  30. private static CrashHandler INSTANCE = new CrashHandler();
  31. //程序的Context对象
  32. private Context mContext;
  33. //用来存储设备信息和异常信息
  34. private Map<String, String> infos = new HashMap<String, String>();
  35. //用于格式化日期,作为日志文件名的一部分
  36. private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
  37. /** 保证只有一个CrashHandler实例 */
  38. private CrashHandler() {
  39. }
  40. /** 获取CrashHandler实例 ,单例模式 */
  41. public static CrashHandler getInstance() {
  42. return INSTANCE;
  43. }
  44. /**
  45. * 初始化
  46. *
  47. * @param context
  48. */
  49. public void init(Context context) {
  50. mContext = context;
  51. //获取系统默认的UncaughtException处理器
  52. mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
  53. //设置该CrashHandler为程序的默认处理器
  54. Thread.setDefaultUncaughtExceptionHandler(this);
  55. }
  56. private String getImei(){
  57. /*TelephonyManager mTm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
  58. return mTm.getDeviceId();*/
  59. return "";
  60. }
  61. private String getModel(){
  62. return Build.MODEL;
  63. }
  64. private int getAndroidVersion(){
  65. return Build.VERSION.SDK_INT;
  66. }
  67. /**
  68. * 当UncaughtException发生时会转入该函数来处理
  69. */
  70. @Override
  71. public void uncaughtException(Thread thread, Throwable ex) {
  72. if (!handleException(ex) && mDefaultHandler != null) {
  73. //如果用户没有处理则让系统默认的异常处理器来处理
  74. mDefaultHandler.uncaughtException(thread, ex);
  75. } else {
  76. try {
  77. Thread.sleep(3000);
  78. } catch (InterruptedException e) {
  79. Log.e(TAG, "error : ", e);
  80. }
  81. //退出程序
  82. android.os.Process.killProcess(android.os.Process.myPid());
  83. GameInterface.finishAllDialog();
  84. System.exit(0);
  85. }
  86. }
  87. /**
  88. * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
  89. *
  90. * @param ex
  91. * @return true:如果处理了该异常信息;否则返回false.
  92. */
  93. private boolean handleException(Throwable ex) {
  94. if (ex == null) {
  95. return false;
  96. }
  97. //使用Toast来显示异常信息
  98. new Thread() {
  99. @Override
  100. public void run() {
  101. Looper.prepare();
  102. //Toast.makeText(mContext, "很抱歉,程序出现异常", Toast.LENGTH_LONG).show();
  103. Looper.loop();
  104. }
  105. }.start();
  106. //收集设备参数信息
  107. collectDeviceInfo(mContext);
  108. //保存日志文件
  109. saveCrashInfo2File(ex);
  110. //保存错误信息到后台云端
  111. saveCrashInfoToWeb(ex);
  112. return true;
  113. }
  114. /**
  115. * 收集设备参数信息
  116. * @param ctx
  117. */
  118. public void collectDeviceInfo(Context ctx) {
  119. try {
  120. PackageManager pm = ctx.getPackageManager();
  121. PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);
  122. if (pi != null) {
  123. String versionName = pi.versionName == null ? "null" : pi.versionName;
  124. String versionCode = pi.versionCode + "";
  125. infos.put("versionName", versionName);
  126. infos.put("versionCode", versionCode);
  127. }
  128. infos.put("apiLevel",String.valueOf(Build.VERSION.SDK_INT));
  129. } catch (PackageManager.NameNotFoundException e) {
  130. // Log.e(TAG, "an error occured when collect package info", e);
  131. }
  132. Field[] fields = Build.class.getDeclaredFields();
  133. for (Field field : fields) {
  134. try {
  135. field.setAccessible(true);
  136. infos.put(field.getName(), field.get(null).toString());
  137. //Log.d(TAG, field.getName() + " : " + field.get(null));
  138. } catch (Exception e) {
  139. //Log.e(TAG, "an error occured when collect crash info", e);
  140. }
  141. }
  142. }
  143. /**
  144. * 保存错误信息到后台云端
  145. *
  146. */
  147. private void saveCrashInfoToWeb(Throwable ex){
  148. String cpuAbi = "";
  149. String cpuAbi2 = "";
  150. String versionName = "";
  151. String versionCode = "";
  152. String apiLevel = "";
  153. String errorMessage = "";
  154. String ramSize = ""; //内存大小
  155. ramSize = getTotalRam(mContext);
  156. for (Map.Entry<String, String> entry : infos.entrySet()) {
  157. String key = entry.getKey();
  158. String value = entry.getValue();
  159. if(key.equals("CPU_ABI")){
  160. cpuAbi = value;
  161. }else if(key.equals("CPU_ABI2")){
  162. cpuAbi2 = value;
  163. }
  164. else if(key.equals("versionName")){
  165. versionName = value;
  166. }
  167. else if(key.equals("versionCode")){
  168. versionCode = value;
  169. }
  170. else if(key.equals("apiLevel")){
  171. apiLevel = value;
  172. }
  173. }
  174. Writer writer = new StringWriter();
  175. PrintWriter printWriter = new PrintWriter(writer);
  176. ex.printStackTrace(printWriter);
  177. Throwable cause = ex.getCause();
  178. while (cause != null) {
  179. cause.printStackTrace(printWriter);
  180. cause = cause.getCause();
  181. }
  182. printWriter.close();
  183. String result = writer.toString();
  184. if(result.contains("android.os.TransactionTooLargeException" ) || result.contains("pthread_create")
  185. || result.contains("Duplicate key in ArrayMap") || result.contains("NullPointerException")){
  186. return;
  187. }
  188. new ErrorDataViewModel(cpuAbi,cpuAbi2,versionName,versionCode,apiLevel,result,ramSize);
  189. }
  190. public void saveCrashInfoToWeb(String msg){
  191. String cpuAbi = "";
  192. String cpuAbi2 = "";
  193. String versionName = "";
  194. String versionCode = "";
  195. String apiLevel = "";
  196. String errorMessage = "";
  197. String ramSize = ""; //内存大小
  198. collectDeviceInfo(mContext);
  199. ramSize = getTotalRam(mContext);
  200. for (Map.Entry<String, String> entry : infos.entrySet()) {
  201. String key = entry.getKey();
  202. String value = entry.getValue();
  203. if(key.equals("CPU_ABI")){
  204. cpuAbi = value;
  205. }else if(key.equals("CPU_ABI2")){
  206. cpuAbi2 = value;
  207. }
  208. else if(key.equals("versionName")){
  209. versionName = value;
  210. }
  211. else if(key.equals("versionCode")){
  212. versionCode = value;
  213. }
  214. else if(key.equals("apiLevel")){
  215. apiLevel = value;
  216. }
  217. }
  218. String result = msg;
  219. if(result.contains("android.os.TransactionTooLargeException" ) || result.contains("pthread_create")
  220. || result.contains("Duplicate key in ArrayMap") || result.contains("NullPointerException")){
  221. return;
  222. }
  223. new ErrorDataViewModel(cpuAbi,cpuAbi2,versionName,versionCode,apiLevel,result,ramSize);
  224. }
  225. //返回内存大小 GB
  226. public String getTotalRam(Context context){
  227. String path = "/proc/meminfo";
  228. String firstLine = null;
  229. int totalRam = 0 ;
  230. try{
  231. FileReader fileReader = new FileReader(path);
  232. BufferedReader br = new BufferedReader(fileReader,8192);
  233. firstLine = br.readLine().split("\\s+")[1];
  234. br.close();
  235. }catch (Exception e){
  236. e.printStackTrace();
  237. }
  238. if(firstLine != null){
  239. totalRam = (int)Math.ceil((new Float(Float.valueOf(firstLine) / (1024 * 1024)).doubleValue()));
  240. }
  241. return totalRam + "GB";//返回1GB/2GB/3GB/4GB
  242. }
  243. /**
  244. * 保存错误信息到文件中
  245. *
  246. * @param ex
  247. * @return 返回文件名称,便于将文件传送到服务器
  248. */
  249. private String saveCrashInfo2File(Throwable ex) {
  250. StringBuffer sb = new StringBuffer();
  251. for (Map.Entry<String, String> entry : infos.entrySet()) {
  252. String key = entry.getKey();
  253. String value = entry.getValue();
  254. sb.append(key + "=" + value + "\n");
  255. }
  256. Writer writer = new StringWriter();
  257. PrintWriter printWriter = new PrintWriter(writer);
  258. ex.printStackTrace(printWriter);
  259. Throwable cause = ex.getCause();
  260. while (cause != null) {
  261. cause.printStackTrace(printWriter);
  262. cause = cause.getCause();
  263. }
  264. printWriter.close();
  265. String result = writer.toString();
  266. sb.append(result);
  267. try {
  268. long timestamp = System.currentTimeMillis();
  269. String time = formatter.format(new Date());
  270. String fileName = "crash-" + time + "-" + timestamp + ".log";
  271. String path = mContext.getExternalCacheDir().getAbsolutePath();
  272. FileOutputStream fos = new FileOutputStream(path + fileName);
  273. fos.write(sb.toString().getBytes());
  274. fos.close();
  275. return fileName;
  276. } catch (Exception e) {
  277. Log.e(TAG, "an error occured while writing file...", e);
  278. }
  279. return null;
  280. }
  281. }