Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”

This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

preface

From the beginning of the contact Android development, the first time to release the version, encountered a program crash, that a panic. Years have passed, and now hear the program crash? Well, let me see what the problem is, and then lock, lock, and fix it.

Reduce bugs and crashes before the release, and don’t panic when you encounter bugs and crashes after the release. After all, bugs won’t be fixed automatically because of your panic, right? Solve the problem as quickly as possible (solving problems is also a sign of competence), and explain the seriousness of the problem, and see if you can just send it out or wait for another time. At the same time, learn lessons to avoid the same problems.

Today we are going to talk about Android flash back. The crash rate of an application determines the quality of the application.

To resolve crashes, The Android system outputs various logs, as well as various third-party libraries, making it much easier for engineers to lock crashes.

To classify crash logs, they can be divided into two categories:

  • JVM Exception stack information as follows:

  • Native code crash log as follows:

JVM exception stack information

There are two types of Exceptions in Java:

  • Check for exceptions.
  • Unchecked Exception: unchecked Exception.

Check for exceptions: At compile time, Android Studio will tell you that the code has an error and will not compile, such as InterruptedException. If we do not catch these exceptions in code, but throw them directly, we may eventually crash the program.

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
Copy the code

Non-check exception: These include errors and runtimeExceptions, which Android Studio does not tell you about at compile time, but rather crash your application at runtime because of code errors. Such as OOM or NullPointerException.

2021- 09 -13 11:50:27.327 19984-19984/com.scc.demo E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.scc.demo, PID: 19984
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.scc.demo/com.scc.demo.actvitiy.HandlerActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
        ...
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
        at com.scc.demo.actvitiy.HandlerActivity.onCreate(HandlerActivity.java:41)
        at android.app.Activity.performCreate(Activity.java:8000)...Copy the code

Java exception

For both exceptions, we can use UncaughtExceptionHandler, which is an internal interface of Thread and is defined as follows:

    public interface UncaughtExceptionHandler {
        /** * The method called when a given Thread terminates due to the given Throwable. * Any exceptions thrown by this method will be ignored by the Java virtual machine. *@param t Thread
         * @param e Throwable
         */
        void uncaughtException(Thread t, Throwable e);
    }
Copy the code

UncaughtException is called if an incoming Thread is terminated because of an “uncaught” exception. It can be used to catch program exceptions indirectly, to record exception information, or to give more friendly exception prompts.

Custom exception handling classes

Custom exception handling classes

A custom class implements the UncaughtExceptionHandler interface and implements the uncaughtException method:

public class SccExceptionHandler implements Thread.UncaughtExceptionHandler {
    private Thread.UncaughtExceptionHandler mDefaultHandler;
    private static SccExceptionHandler sccExceptionHandler;
    private Context mContext;

    public static SccExceptionHandler getInstence(a) {
        if (sccExceptionHandler == null) {
            synchronized (SccExceptionHandler.class) {
                sccExceptionHandler = newSccExceptionHandler(); }}return sccExceptionHandler;
    }

    public void init(Context context) {
        mContext = context;
        // The exception handler is not caught by default
        //the default uncaught exception handler for all threads
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
        // Set the current Handler to the system default
        Thread.setDefaultUncaughtExceptionHandler(this);

    }

    @Override
    public void uncaughtException(@NonNull @NotNull Thread t, @NonNull @NotNull Throwable e) {
        if(! handlerUncaughtException(e) && mDefaultHandler ! =null) {
            // Note 1: System processing
            mDefaultHandler.uncaughtException(t, e);
        } else {
            // Note 2: Do it yourself
            Intent intent = new Intent(mContext, ImageViewActivity.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK);
            mContext.startActivity(intent);
            // Terminate the process
            android.os.Process.killProcess(android.os.Process.myPid());
            // Terminates the currently running Java VIRTUAL machine.
            // Parameters are used as status codes; By convention, a non-zero status code indicates an abnormal termination.
            System.exit(0); }}// The handler did not catch an exception
    private boolean handlerUncaughtException(Throwable e) {
        1. Collect crash site information, such as the current App version information, device information, and exception information.
        //2. Record logs (e.g. save them locally), and wait for developers to troubleshoot problems or upload them to the server when the APP is started next time.
        return true;
        // do not want to process return false;}}Copy the code

Note 1: You need to hold the thread default exception handling class in the custom exception handling class. The purpose of this is to hand the exception to the system for default handling if the custom exception handling class fails or fails to handle the exception.

Note 2: If the custom exception handler class successfully handles the exception, you need to jump to the page or “kill” the program process. Otherwise, the program will always be stuck in the crash interface, and the pop-up no response dialog box.

Android.os.process.mypid () : Returns the identifier of this Process, which can be used with killProcess and sendSignal.

Android. OS. Process. KillProcess (android. OS. Process. MyPid ()) : using a given PID terminate the Process. Note that while this API allows us to terminate any process based on its PID request, the kernel still imposes standard restrictions on the Pids you can actually terminate. Typically this means only the process running the caller’s package/application and any other processes created by that application; Packages that share a common UID will also be able to kill each other’s processes.

Use custom exception handling classes

Once SccExceptionHandler is defined, you can initialize it and register the main thread with SccExceptionHandler. As follows:

public class SccApp extends Application {
    @Override
    public void onCreate(a) {
        super.onCreate();
        SccExceptionHandler.getInstence().init(this); }}Copy the code

Native exception

When native code crashes, a detailed crash log is stored in the /data/tombstones/ directory. Since I am not very familiar with Native, I will not mislead you. I will play by myself if I am interested.

For the introduction of program crash signal mechanism, you can refer to this article from Tencent: Crash capture mechanism and implementation of Native code of Android platform

Online crash log capture

The Java and Native crash capture described above is based on the assumption that you can reproduce the bug. But for online users, this approach is not practical.

For most companies, there is no need to implement a log-fetching platform for the online version. The fastest way to do this is to integrate third-party SDKS. At present, more mature, more use is Tencent’s Bugly.

Bugly

Bugly can basically meet all the requirements of online version to capture crash, including the corresponding logs of Java layer and Native layer crash. Every day, Bugly will send an email to the crash log of the previous day, facilitating testing and development of statistical bug distribution and crash rate.

Access to the document

Abnormal summary

Collapse analysis

I didn’t make any changes to the crash analysis part, which was automatically captured by Bugly.

Error analysis

The specific content

This is where I store the parameters and returned data to the server when requesting the interface. , let’s look at the concrete effect.

It is quite convenient to use, and provides a solution for errors.

xCrash

XCrash provides android apps with the ability to catch Java crashes, Native crashes and ANR. No root permissions or any system permissions are required.

XCrash can generate a tombstone file (similar to android’s tombstone file) in your specified directory in the event of an app crash or ANR.

XCrash has been used in many Android apps (including IQiyi videos) on different iQiyi platforms (mobile, tablet, TV) for many years.

XCrash portal

Sentry

Sentry is a service that helps you monitor and fix crashes in real time. The server uses Python, but it contains a full API for sending events from any language in any application.

Sentry portal

XCrash and Sentry, both of which have an advantage over Bugly in that in addition to automatically blocking interface crashes, they can also actively report errors.

It can be seen that the use of XCrash is more flexible and the engineers have higher control. You can set different filtering modes to report corresponding crash logs. In addition, after capturing crash, customized operations can be added, such as local log saving or direct network uploading.

Another advantage of Sentry is that it can be filtered to determine whether crash logs are reported. This is useful for SDK developers. For example, some SDK developers just want to collect crash introduced by their OWN SDK and filter crash caused by other user operations. In this case, Sentry integration can be considered.

Bugly easy to use

Feel the tutorial messy can go to the above to find their own Buyle document integration, very simple.

Library file import

Automatic integration (recommended)

plugins {
    id 'com.android.application'
}
android {
    compileSdkVersion 30// The compiled version of the project
    defaultConfig {
        applicationId "com.scc.demo"/ / package name
        minSdkVersion 23// The lowest compatible version of Android
        targetSdkVersion 30// Target version, indicating that you have done enough testing on the Android version
        versionCode 1/ / version number
        versionName "1.0.0"// Version name
        ndk {
            abiFilters 'armeabi-v7a'.'arm64-v8a'.'x86'
            // Run environment, to upload Google Play must be compatible with 64 bits, here only compatible with ARM architecture
            For the ARM architecture, the 32-bit libraries are in Armeabi-v7a. The 64-bit equivalent is ARM64-V8A.
            For x86 architectures, look for x86 (for 32-bit) and x86_64 (for 64-bit).
        }
    }
}

dependencies {
    implementation 'com. Tencent. Bugly: crashreport: 3.4.4'
    // When integrating Bugly NDK, you need to integrate Bugly SDK.
    implementation 'com. Tencent. Bugly: nativecrashreport: 3.9.2'

}
Copy the code

Note: Automatic integration will automatically include the Bugly SO library. It is recommended to use the NDK “abiFilter” configuration in the Build. gradle file of the Module to set the supported SO library architecture.

Android Studio displays the following message after adding “abiFilter” :

NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin.

Add the gradle.properties file in the root directory of your project:

android.useDeprecatedNdk=true

Initialize the

public class SccApp extends Application {
    @Override
    public void onCreate(a) {
        super.onCreate();
        //70594a1ff8 Bugly App ID of the new product
        CrashReport.initCrashReport(getApplicationContext(), "70594a1ff8".false); }}Copy the code

Error analysis

Set up the

    private void setCrashReport(String url, String name, Map<String, String> params, String message) {
        try {
            if(params ! =null&&! MStringUtils.isNullOrEmpty(url) && ! MStringUtils.isNullOrEmpty(name) && ! MStringUtils.isNullOrEmpty(params.toString()) && ! MStringUtils.isNullOrEmpty(message)) { CrashReport.putUserData(AppGlobalUtils.getApplication(),"SccParams", params.toString());
                CrashReport.putUserData(AppGlobalUtils.getApplication(), "Data"."LoginName-Scc001:" + message);
                CrashReport.postCatchedException(new RuntimeException(name + ":" + url + ":"+ message)); }}catch (Exception e) {
        }
    }
Copy the code

call

        HashMap<String,String> hashMap = new HashMap<>();
        hashMap.put("name"."scc001");
        hashMap.put("pass"."111111");
        String returnData = "Ha ha ha ha ha.";
        setCrashReport("loin/register"."Main",hashMap,returnData);
Copy the code

The effect

Error list

Error details

The error stack

Trace data

Collapse analysis

You don’t have to set this up yourself, Bugly automatic fetching, and the following provides a similar function to error analysis that I won’t describe here.

That’s the end of this article. Hope to help you quickly lock the bug and solve, make the application more perfect, let your boss more assured, more tickets to some.

Phase to recommend

❤️Android installation package packing process ❤️

❤️Android installation package volume optimization ❤️

❤️ Android source code interpretation – how is the application launched ❤️

❤️ Android source code interpretation -startActivity()❤️