Android Crashキャプチャ処理

15669 ワード

一、Android Crash説明
  • プログラムがキャプチャされていない異常によって突然終了すると、システムはプロセッサのインタフェースU n c a u ghtExceptionHandlerを呼び出す.
  • プログラムによって正常にキャプチャされていない異常を処理するには、このインタフェースのUncaughtExceptionHandlerメソッドを実現するだけで、UncaughtExceptionHandlerメソッドはThreadとThrowableの2つのパラメータを返します.

  • 二、実現構想
  • まず崩壊した携帯電話の情報を収集します.Androidの試作機は種類が多く、特定の機種では不思議なバグが発生する可能性が高いからです.
  • は、携帯電話の情報とクラッシュ情報をファイルシステムに書き込む.このように後続の処理を便利にする.
  • クラッシュしたアプリケーションは、自動的に再起動する必要があります.再起動したページはフィードバックページに設定され、ユーザーにクラッシュレポートをアップロードする必要があるかどうかを尋ねる.
  • ユーザが同意すると、書き込まれるクラッシュ情報ファイルが自分のサーバに送信される.

  • 三、コード展示
  • CrashApplication.java
      import android.app.Application;
      import android.os.Handler;
      import android.util.Log;
    
      public class CrashApplication extends Application{
          /** TAG */
          public static final String TAG = "CrashApplication";
          @Override
          public void onCreate() {
              super.onCreate();
              CrashHandler.getInstance().init(this);
              Log.v(TAG, "application created");
          }
      }   
    
  • CrashHandler.java
      import java.io.BufferedWriter;
      import java.io.File;
      import java.io.FileWriter;
      import java.io.IOException;
      import java.io.PrintWriter;
      import java.io.StringWriter;
      import java.io.Writer;
      import java.lang.Thread.UncaughtExceptionHandler;
      import java.lang.reflect.Field;
      import java.text.DateFormat;
      import java.text.SimpleDateFormat;
      import java.util.Date;
      import java.util.HashMap;
      import java.util.Map;
    
      import android.app.AlarmManager;
      import android.app.PendingIntent;
      import android.content.Context;
      import android.content.Intent;
      import android.content.pm.PackageInfo;
      import android.content.pm.PackageManager;
      import android.content.pm.PackageManager.NameNotFoundException;
      import android.os.AsyncTask;
      import android.os.Build;
      import android.os.Environment;
      import android.util.Log;
    
      public class CrashHandler implements UncaughtExceptionHandler{
    
          /** TAG */
          private static final String TAG = "CrashHandler";
    
          /**
           *  uploadUrl 
           *        ,           
          **/
          private static final String uploadUrl = "http://3.saymagic.sinaapp.com/ReceiveCrash.php";
    
          /**
           * localFileUrl
           *   log       
           **/
          private static String localFileUrl = "";
          
          /** mDefaultHandler */
          private Thread.UncaughtExceptionHandler defaultHandler;
    
          /** instance */
          private static CrashHandler instance = new CrashHandler();
    
          /** infos */
          private Map infos = new HashMap();
    
          /** formatter */
          private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
          /** context*/
          private CrashApplication context;
          private CrashHandler() {}
    
          public static CrashHandler getInstance() {
              if (instance == null) {
                  instance = new CrashHandler();
              }
              return instance;
          }
    
          /**
           * @param ctx
           *    ,     Application OnCreate        
           */
          public void init(CrashApplication ctx) {
              this.context = ctx;
              defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
              Thread.setDefaultUncaughtExceptionHandler(this);
          }
    
          /**
           * uncaughtException
           *          Exception
           */
          @Override
          public void uncaughtException(Thread thread, Throwable throwable) {
              handleException(throwable);
              defaultHandler.uncaughtException(thread, throwable);
          }
          private boolean handleException(Throwable ex) {
              if (ex == null) {
                  return false;
              }
              Log.d("TAG", "    ");
              collectDeviceInfo(context);
              writeCrashInfoToFile(ex);
              restart();
              return true;
          }
    
          /**
           * 
           * @param ctx
           *         
           */
          public void collectDeviceInfo(Context ctx) {
              try {
                  PackageManager pm = ctx.getPackageManager();
                  PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(),
                          PackageManager.GET_ACTIVITIES);
                  if (pi != null) {
                      String versionName = pi.versionName == null ? "null"
                              : pi.versionName;
                      String versionCode = pi.versionCode + "";
                      infos.put("versionName", versionName);
                      infos.put("versionCode", versionCode);
                      infos.put("crashTime", formatter.format(new Date()));
                  }
              } catch (NameNotFoundException e) {
                  Log.e(TAG, "an error occured when collect package info", e);
              }
              Field[] fields = Build.class.getDeclaredFields();
              for (Field field: fields) {
                  try {
                      field.setAccessible(true);
                      infos.put(field.getName(), field.get(null).toString());
                      Log.d(TAG, field.getName() + " : " + field.get(null));
                  } catch (Exception e) {
                      Log.e(TAG, "an error occured when collect crash info", e);
                  }
              }
          }
    
          /**
           * 
           * @param ex
           *          
           */
          private void writeCrashInfoToFile(Throwable ex) {
              StringBuffer sb = new StringBuffer();
              for (Map.Entry entry: infos.entrySet()) {
                  String key = entry.getKey();
                  String value = entry.getValue();
                  sb.append(key + "=" + value + "
    "); } 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(); sb.append(result); // SD Log if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { String sdcardPath = Environment.getExternalStorageDirectory().getPath(); String filePath = sdcardPath + "/cym/crash/"; localFileUrl = writeLog(sb.toString(), filePath); } } /** * * @param log * @param name * @return * Log , SD */ private String writeLog(String log, String name) { CharSequence timestamp = new Date().toString().replace(" ", ""); timestamp = "crash"; String filename = name + timestamp + ".log"; File file = new File(filename); if(!file.getParentFile().exists()){ file.getParentFile().mkdirs(); } try { Log.d("TAG", " SD "); // FileOutputStream stream = new FileOutputStream(new File(filename)); // OutputStreamWriter output = new OutputStreamWriter(stream); file.createNewFile(); FileWriter fw=new FileWriter(file,true); BufferedWriter bw = new BufferedWriter(fw); // Log bw.write(log); bw.newLine(); bw.close(); fw.close(); return filename; } catch (IOException e) { Log.e(TAG, "an error occured while writing file...", e); e.printStackTrace(); return null; } } private void restart(){ try{ Thread.sleep(2000); }catch (InterruptedException e){ Log.e(TAG, "error : ", e); } Intent intent = new Intent(context.getApplicationContext(), SendCrashActivity.class); PendingIntent restartIntent = PendingIntent.getActivity( context.getApplicationContext(), 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK); // AlarmManager mgr = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent); // 1 } }
  • MainActivity.java
      import android.app.Activity;
      import android.os.Bundle;
      import android.view.Menu;
      import android.view.View;
      import android.widget.Toast;
    
      public class MainActivity extends Activity {
    
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_main);
          }
    
          /**
           *            
           * @param view
           */
          public void generateCrash(View view){
              int a = 2/0;
          }
      }
    
  • SendCrashActivity.java
      import java.io.File;
    
      import android.app.Activity;
      import android.os.AsyncTask;
      import android.os.Bundle;
      import android.os.Environment;
      import android.util.Log;
      import android.view.Menu;
      import android.view.View;
      import android.widget.Toast;
    
      /**
       *   crash activity。 activity          。
       */
      public class SendCrashActivity extends Activity {
    
          private static final String uploadUrl = "http://3.saymagic.sinaapp.com/ReceiveCrash.php";
    
          /**
           * localFileUrl
           *   log       
           */
          private static String localFileUrl = "";
          
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_send_crash);
              //             SD  Log    
              if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                  String sdcardPath = Environment.getExternalStorageDirectory().getPath();
                  localFileUrl = sdcardPath + "/cym/crash/crash.log";
              }
          }
    
          public void sendCrash(View view){
              new SendCrashLog().execute("");
          }
          @Override
          public boolean onCreateOptionsMenu(Menu menu) {
              // Inflate the menu; this adds items to the action bar if it is present.
              getMenuInflater().inflate(R.menu.send_crash, menu);
              return true;
          }
          /**
           *           
           */
          public class SendCrashLog extends AsyncTask {
              public SendCrashLog() {  }
    
              @Override
              protected Boolean doInBackground(String... params) {
                  Log.d("TAG", "          ");
                  UploadUtil.uploadFile(new File(localFileUrl), uploadUrl);
                  return null;
              }
    
              @Override
              protected void onPostExecute(Boolean result) {
                  Toast.makeText(getApplicationContext(), "             ,      ", 1000).show();
                  Log.d("TAG", "    ");   
              }
          }
      }
    
  • UploadUtil.java
      import java.io.DataOutputStream;
      import java.io.File;
      import java.io.FileInputStream;
      import java.io.IOException;
      import java.io.InputStream;
      import java.net.HttpURLConnection;
      import java.net.MalformedURLException;
      import java.net.URL;
      import java.util.UUID;
    
      import android.util.Log;
    
      public class UploadUtil {
    
          private static final String TAG = "UPLOADUTIL";
          private static final int TIME_OUT = 10*1000;
          private static final String CHARSET = "utf-8";
    
          public static String uploadFile(File file,String requestUrl){
              String result = null;
              String  BOUNDARY =  UUID.randomUUID().toString();  //           
              String PREFIX = "--" ;
              String LINE_END = "\r
    "; String CONTENT_TYPE = "multipart/form-data"; // try{ URL url = new URL(requestUrl); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(TIME_OUT); conn.setConnectTimeout(TIME_OUT); conn.setDoInput(true); // conn.setDoOutput(true); // conn.setUseCaches(false); // conn.setRequestMethod("POST"); // conn.setRequestProperty("Charset", CHARSET); // conn.setRequestProperty("connection", "keep-alive"); conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY); if(file!=null) { /** * , */ DataOutputStream dos = new DataOutputStream(conn.getOutputStream()); StringBuffer sb = new StringBuffer(); sb.append(PREFIX); sb.append(BOUNDARY); sb.append(LINE_END); /** * : * name key key * filename , :abc.png */ sb.append("Content-Disposition: form-data; name=\"uploadcrash\"; filename=\""+file.getName()+"\""+LINE_END); sb.append("Content-Type: application/octet-stream; charset="+CHARSET+LINE_END); sb.append(LINE_END); dos.write(sb.toString().getBytes()); InputStream is = new FileInputStream(file); byte[] bytes = new byte[1024]; int len = 0; while((len=is.read(bytes))!=-1) { dos.write(bytes, 0, len); } is.close(); dos.write(LINE_END.getBytes()); byte[] end_data = (PREFIX+BOUNDARY+PREFIX+LINE_END).getBytes(); dos.write(end_data); dos.flush(); /** * 200= * , */ int res = conn.getResponseCode(); Log.e(TAG, "response code:"+res); // if(res==200) // { Log.e(TAG, "request success"); InputStream input = conn.getInputStream(); StringBuffer sb1= new StringBuffer(); int ss ; while((ss=input.read())!=-1) { sb1.append((char)ss); } result = sb1.toString(); Log.e(TAG, "result : "+ result); // } // else{ // Log.e(TAG, "request error"); // } } }catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return result; } }