How does Android collect crash information about published programs

  • 2020-05-17 06:27:05
  • OfStack

When we write a program, we want to write a program that doesn't have any Bug in it, and we don't expect it to crash under any circumstances. But the ideal is full, the reality is bone. No programmer can guarantee that a program he writes will never crash unexpectedly. Especially for applications with a few hundred million users, when you have an order of magnitude of users, you should not be surprised if you have a few unusual crashes.

Since any program we write is subject to an abnormal crash, if it is an unreleased program, we can analyze it by testing grab Log. However, with a published application, we can't reproduce the phenomenon, so it's important to get user feedback. Let's talk about how to collect exception information about the program running process.

1. Android exception capture interface


// When a thread terminates abruptly because of an uncaught exception, the handler's interface is called 
static interface UncaughtExceptionHandler

2. Set the thread to catch exceptions
From the above interface we can see that this interface is for threads, that is to say, if we need to monitor the running of a thread, we only need to implement this interface and then set the monitoring method into a specific thread. 1 generally speaking, the thing we need to monitor most is our UI thread, the main thread.

// Sets the default handler to be invoked when a thread terminates abruptly because an exception is not caught and no other handler is defined for that thread. 
static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh) 

3. Example of UncaughtExceptionHandler

class MythouCrashHandler implements UncaughtExceptionHandler 
{
    private static final String TAG = "MythouCrashHandler---->";
    private UncaughtExceptionHandler defaultUEH;
  // Constructor to get the default processing method 
    public MythouCrashHandler() 
    {
        this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
    }
  // This interface must be rewritten to handle our exception information 
    @Override
    public void uncaughtException(Thread thread, Throwable ex) 
    {
        final Writer result = new StringWriter();
        final PrintWriter printWriter = new PrintWriter(result);
     // Get the tracking stack information, in addition to the system stack information, also put the phone model, system version, build version only 1 mark 
        StackTraceElement[] trace = ex.getStackTrace();
        StackTraceElement[] trace2 = new StackTraceElement[trace.length+3];
        System.arraycopy(trace, 0, trace2, 0, trace.length);
        trace2[trace.length+0] = new StackTraceElement("Android", "MODEL", android.os.Build.MODEL, -1);
        trace2[trace.length+1] = new StackTraceElement("Android", "VERSION", android.os.Build.VERSION.RELEASE, -1);
        trace2[trace.length+2] = new StackTraceElement("Android", "FINGERPRINT", android.os.Build.FINGERPRINT, -1);
    // Append information because the default processing method is called back later 
        ex.setStackTrace(trace2);
        ex.printStackTrace(printWriter);
     // Turn the stack information obtained above into a string and print it out 
        String stacktrace = result.toString();
        printWriter.close();
        Log.e(TAG, stacktrace);
        // So I'm just going to write the exception stack information SD The card Log Log in 
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) 
        {
            String sdcardPath = Environment.getExternalStorageDirectory().getPath();
            writeLog(stacktrace, sdcardPath + "/mythou");
        }
        defaultUEH.uncaughtException(thread, ex);
    }
  // write Log Method of information, write to SD Cary surface 
    private void writeLog(String log, String name) 
    {
        CharSequence timestamp = DateFormat.format("yyyyMMdd_kkmmss", System.currentTimeMillis());
        String filename = name + "_" + timestamp + ".log";
        try 
        {
            FileOutputStream stream = new FileOutputStream(filename);
            OutputStreamWriter output = new OutputStreamWriter(stream);
            BufferedWriter bw = new BufferedWriter(output);
       // Write relevant Log To the file 
            bw.write(log);
            bw.newLine();
            bw.close();
            output.close();
        } 
        catch (IOException e) 
        {
            e.printStackTrace();
        }
    }
}

Above is the implementation of the method to get the processing trace information, the above method is written in reference to VLC's exception handling mechanism. Some simple changes were made. However, it only gets abnormal information. If the program is installed on the user's machine, we cannot get such information. We cannot ask the user to bring the machine to you, and then you can copy Log. (I tried this before when I was doing embeddability. I asked the customer to take the machine and copy the Log inside. At that time, the machine could not be connected to the Internet. In order to no longer be bothered, we need a function that can send Log to our server. The following is to send a service information to our designated server function.

3. Send Log over the network

   public class SendCrashLog extends AsyncTask<String, String, Boolean> 
    {
        public SendCrashLog() { }
        @Override
        protected Boolean doInBackground(String... params) 
        {
            if (params[0].length() == 0)
                return false;
            HttpClient httpClient = new DefaultHttpClient();
       // Your server, this is just an example. Treat the exception message as http The request is sent to the server 
            HttpPost httpPost = new HttpPost("http://www.mythou/getlog.php");
       // The relevant exception information is converted here http post The data parameters of the request 
            try {
                List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
                nameValuePairs.add(new BasicNameValuePair("model", params[0]));
                nameValuePairs.add(new BasicNameValuePair("device", params[1]));
                httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
         // Send relevant request information 
                httpClient.execute(httpPost);
            } catch (ClientProtocolException e) {
                e.printStackTrace();
                return false;
            } catch (IOException e) {
                e.printStackTrace();
                return false;
            }
            Log.d(TAG, "Device model sent.");
            return true;
        }
        @Override
        protected void onPostExecute(Boolean result) {
        }
    }

The above is the use of asynchronous tasks that I discussed in the last article. In the asynchronous task, we wrote a service to send http request, which is used to send the relevant exception information to the specified server. This requires your server to parse the sent http request, which is not too difficult. Anyone who wants to make an web knows how to do it. In the above exception handling, call the send method here:

SendCrashLogsendLog = new SendCrashLog();
// The exception message string 
sendLog .execute(stacktrace);

Through the above method can send the exception information to the specified server, also can track the customer's use of the software, so that we can modify the program. Of course, this information collection 1 general privacy and background traffic problems, this needs to do some hints in the program, so as not to back up the abuse of rogue software.


Related articles: