How many ANRs are generated by thread.sleep () in the onCreate/onReceive methods of the four major components?

Application Not Responding (ANR) ¶ Application Not Responding (ANR) ¶ Application Not Responding (ANR) ¶ Is it the same as what you think? If not, you can look at my analysis below. Elapsed time means that the current Thread is stagnant and no longer executes subsequent logic, so thread.sleep () is used here (elapsed time means sleep).

ANR(Application Not Responding) refers to an Application that is Not Responding. An “Application Not Responding” (ANR) error will be emitted if the Android Application’s interface thread remains blocked for too long. If the application is in the foreground, a dialog box is displayed to the user, as shown in Figure 1. The ANR dialog provides the user with the option to forcibly exit the application.

What scenarios contribute to ANR?

  • Service Timeout: For example, the foreground Service is not executed within 20 seconds

    • For the foreground service, the timeout is SERVICE_TIMEOUT = 20s
    • For background services, the timeout value is SERVICE_BACKGROUND_TIMEOUT = 200s
  • BroadcastQueue Timeout: for example, BroadcastQueue Timeout is not completed within 10 seconds

    There are two foreground queues and background queues for broadcast queues:

    • For foreground broadcasts, the timeout is BROADCAST_FG_TIMEOUT = 10s
    • For background broadcasts, the timeout is BROADCAST_BG_TIMEOUT = 60s
  • ContentProvider Timeout: the ContentProvider publishes 10 seconds after the Timeout

    ContentProvider Timeout is triggered when ams.mainHandler in the “ActivityManager” thread receives a CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG message.

  • InputDispatching Timeout: The input event dispatching Timeout is 5s, including key strokes and touch events.

Verify the title query

Let’s start with thread.sleep (21_000) in the onCreate/onReceive methods of each of the four components and Application (incidentally tested).

Activity

The first is onCreate in the Activity

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test2);
        Log.i(TAG, "onCreate: ");
        try {
            Thread.sleep(21 _000);
            Log.i(TAG, "onCreate: ====2");
        } catch(InterruptedException e) { e.printStackTrace(); }}Copy the code

There is no ANR, nor is there any of the scenarios summarized above. Some people may understand that a time-consuming operation on the main thread causes ANR, which means the application is not responding, but a time-consuming operation does not necessarily cause no response.

To verify this, set the button click event in the onCreate method

        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) { sleepTest(); }});Copy the code

Details of the sleepTest method

public void sleepTest(a){
    new Handler().postDelayed(new Runnable() {
        @Override
        public void run(a) {
            Button button = findViewById(R.id.btn);
            button.setText("jackie"); }},7000);
    try {
        Thread.sleep(21 _000);
        Log.i(TAG, "onCreate: ====2");
    } catch(InterruptedException e) { e.printStackTrace(); }}Copy the code

Click the button, does ANR happen, and the answer is no. So that’s why the time consuming operation doesn’t necessarily result in no response, just like the onCreate method did with sleep, but if you hit the button and then hit the back button, then you get an ANR, because the main thread is asleep, you hit the button and there’s no response for 5 seconds, then you get an ANR.

Service

The onCreate method in the Service creates a foreground Service (20s) by default to start the Activity, which results in an ANR.

    @Override
    public void onCreate(a) {
        super.onCreate();
        try {
            Log.i(TAG, "onCreate: ====1===");
            //Thread.sleep(19000); // AnR does not occur
            Thread.sleep(21000); //发生anr
            Log.i(TAG, "onCreate: ====2====");
        } catch(InterruptedException e) { e.printStackTrace(); }}Copy the code
ContentProvider
@Override
public boolean onCreate(a) {
    Log.i(TAG, "onCreate: ===1====");
    try {
        Thread.sleep(21 _000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    Log.i(TAG, "onCreate: =====2=======");
    return false;
}
Copy the code

The ANR is not generated. The ContentProvider publishes a timeout of 10 seconds. Emitted when ams. MainHandler in the “ActivityManager” thread receives the CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG message. By looking at the ContentProvider source code and the startup process, we can see that onCreate is executed before publish, so no ANR is created in onCreate.

BroadcastReceiver

Send broadcast

Intent intent = new Intent("android.intent.jackie");
// Set to foreground broadcast. Default is background broadcast
intent.setPackage(getPackageName()); // The package name must be set. Otherwise, anR cannot be displayed
//intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Test2Activity.this.sendBroadcast(intent);
Copy the code

Execution time in onReceive

public class TestBroadcastReceiver extends BroadcastReceiver {
    private static final String TAG = "TestBroadcastReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG, "onReceive: ===1====");
        try {
            // This is not the case
            //Thread.sleep(9000); // AnR does not occur
            Thread.sleep(21 _000); //发生anr
            // This is the first time that you can get a message
            //Thread.sleep(65000); //发生anr
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Log.i(TAG, "onReceive: ===2===="); }}Copy the code

For foreground broadcasts, the timeout value is BROADCAST_FG_TIMEOUT = 10s, and the duration of background broadcasts is 60s. So this is going to produce ANR. Note that the packet name of the intent is added when sending a broadcast.

Application

By the way, do the Application test

@Override
public void onCreate(a) {
    super.onCreate();
    Log.i(TAG, "onCreate: ==a===");
    try {
        Thread.sleep(21 _000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    Log.i(TAG, "onCreate: ===b===");

}
Copy the code

ANR does not occur, ANR in Android does not have this scenario.

summary

In addition to the ANR caused by the input event, we can compare other ANR to detonating a bomb, so the whole process consists of three parts:

  1. Buried time bomb: central control system (system_server process) start countdown, in the specified time if the target (application process) did not finish all the work, the central control system will be directed to blow up (kill process) target.
  2. Bomb demolition: in the specified time to finish all the work site, and timely report to the central control system to complete, request to remove the time bomb, it survived.
  3. Detonate bomb: central control system immediately encapsulate the scene, capture snapshots, collect the target execution slow traces, facilitate the follow-up case detection (debugging analysis), and finally blow up the target.

The process of ANR can be divided into burying bomb -> disarming bomb -> detonating bomb. If the buried bomb is not removed within a certain period of time, that is, ** sending delayed message is not removed within a certain period of time, then it will detonate (trigger) and generate ANR. ** A detailed analysis can be found in this article.

ANR due to input events (special)

One more soul search:

Set thread.sleep (10_000) to a button click event in an Activity. Does it cause ANR if it is clicked twice in a row or three times?

        findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    Thread.sleep(10 _000);
                } catch(InterruptedException e) { e.printStackTrace(); }}});Copy the code

On Android29 (the previous version has not been tested, it is expected to be the same), two clicks in a row will not cause ANR, for input events, if only click without subsequent click input events will not cause ANR, but didn’t we click twice in a row? Since the first click event has already been consumed, we only sleep in onClick, and then we click on the second one, which only has an input event and no subsequent click input, so no ANR is generated.

If we click three times in a row, excluding the first consumption, there will be successive inputs, which will produce ANR. If we write Thread.sleep in onTouch, we only need one click because the method will be called back twice, with down and up being two input times. Note: if it is a key event (if the return key is clicked), if the main thread is in sleep(), then the return key is clicked, 5s does not respond, directly throws ANR.

Changes on Android R

On Android R (11), only two clicks in a row are required to create ANR. The input mechanism has been greatly adjusted in this version. If you are interested, you can explore it by yourself.

How to design an ANR listener manually

FileObserver

After ANR is sent in Android, the Android system will output ANR Log to /data/ ANR /trace. TXT. ** This solution is to listen for trace. TXT file. ** In Android, files can be monitored using FileObserver. FileObserver is a listener used to listen for files to be accessed, created, modified, deleted, moved, etc. However, the common user app in android5.0 may not have the permission to realize the file monitoring, some system apps can be implemented in this way.

public class ANRFileObserver extends FileObserver {


    public ANRFileObserver(String path) {//data/anr/
        super(path);
    }

    public ANRFileObserver(String path, int mask) {
        super(path, mask);
    }

    @Override
        public void onEvent(int event, @Nullable String path) {
            switch (event)
        {
            case FileObserver.ACCESS:// The file is accessed
                Log.i("Jackie"."ACCESS: " + path);
                break;
            case FileObserver.ATTRIB:// File attributes are modified, such as chmod, chown, touch, etc
                Log.i("Jackie"."ATTRIB: " + path);
                break;
            case FileObserver.CLOSE_NOWRITE:// Cannot write files to be closed
                Log.i("Jackie"."CLOSE_NOWRITE: " + path);
                break;
            case FileObserver.CLOSE_WRITE:// The writable file is closed
                Log.i("Jackie"."CLOSE_WRITE: " + path);
                break;
            case FileObserver.CREATE:// Create a new file
                Log.i("Jackie"."CREATE: " + path);
                break;
            case FileObserver.DELETE:// The file was deleted, such as rm
                Log.i("Jackie"."DELETE: " + path);
                break;
            case FileObserver.DELETE_SELF:// Self-delete, that is, an executable deletes itself at execution time
                Log.i("Jackie"."DELETE_SELF: " + path);
                break;
            case FileObserver.MODIFY:// The file is modified
                Log.i("Jackie"."MODIFY: " + path);
                break;
            case FileObserver.MOVE_SELF:// Self-moving, that is, an executable file moves itself during execution
                Log.i("Jackie"."MOVE_SELF: " + path);
                break;
            case FileObserver.MOVED_FROM:// The file is removed, such as mv
                Log.i("Jackie"."MOVED_FROM: " + path);
                break;
            case FileObserver.MOVED_TO:// The file is moved, such as mv, cp
                Log.i("Jackie"."MOVED_TO: " + path);
                break;
            case FileObserver.OPEN:// The file is opened
                Log.i("Jackie"."OPEN: " + path);
                break;
            default:
                / / CLOSE: a file is closed, is equal to (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
                //ALL_EVENTS: includes all of the above events
                Log.i("Jackie"."DEFAULT(" + event + ")." + path);
                break; }}}Copy the code
ANRWatchDog

As we know, Android is based on message processing mechanism, the whole program runs in a loop, and the message is distributed by handler. Therefore, we can start a thread to send messages to our main thread periodically through handler. If the message is not processed for a certain time, We can tell that ANR has occurred.

public class ANRWatchDog extends Thread {

    private static final String TAG = "ANR";
    private int timeout = 5000;
    private boolean ignoreDebugger = true;

    static ANRWatchDog sWatchdog;

    private Handler mainHandler = new Handler(Looper.getMainLooper());

    private class ANRChecker implements Runnable{

        private boolean mCompleted;
        private long mStartTime;
        // This value records the elapsed time between system startup and the current time
        private long executeTime = SystemClock.uptimeMillis();

        @Override
        public void run(a) {
            synchronized (ANRWatchDog.this) {
                mCompleted = true; executeTime = SystemClock.uptimeMillis(); }}void schedule(a) {
            mCompleted = false;
            mStartTime = SystemClock.uptimeMillis();
            // Post to the front of the queue each time
            mainHandler.postAtFrontOfQueue(this);
        }

        boolean isBlocked(a) {
            return! mCompleted || executeTime - mStartTime >=5000; }}public interface ANRListener {
        void onAnrHappened(String stackTraceInfo);
    }

    private ANRChecker anrChecker = new ANRChecker();

    private ANRListener anrListener;

    public void addANRListener(ANRListener listener){
        this.anrListener = listener;
    }

    public static ANRWatchDog getInstance(a){
        if(sWatchdog == null){
            sWatchdog = new ANRWatchDog();
        }
        return sWatchdog;
    }

    private ANRWatchDog(a){
        super("ANR-WatchDog-Thread");
    }

    @Override
    public void run(a) {
        //super.run();
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); // Set it to background thread
        while (true) {while(! isInterrupted()){synchronized (this){
                    anrChecker.schedule();
                    long waitTime = timeout;
                    long start = SystemClock.uptimeMillis();
                    // Make sure to sleep for a certain amount of time to prevent false awakenings
                    while (waitTime > 0) {try{
                            wait(waitTime);
                        } catch (InterruptedException e){
                            Log.w(TAG, "run: ", e);
                        }
                        waitTime = timeout - (SystemClock.uptimeMillis() - start);
                    }
                    if(! anrChecker.isBlocked()){continue; }}if(! ignoreDebugger && Debug.isDebuggerConnected()){continue;
                }
                String stackTraceInfo = getStackTraceInfo();
                if(anrListener ! =null){
                    anrListener.onAnrHappened(stackTraceInfo);
                }
            }
            anrListener = null; }}private String getStackTraceInfo(a) {
        StringBuilder stringBuilder = new StringBuilder();
        for (StackTraceElement stackTraceElement : Looper.getMainLooper().getThread().getStackTrace()) {
            stringBuilder
                    .append(stackTraceElement.toString())
                    .append("\r\n");
        }
        returnstringBuilder.toString(); }}Copy the code

Simulate ANR scenarios

void ANRTest(a){
    handler = new Handler();
    ANRWatchDog.getInstance().addANRListener(new ANRWatchDog.ANRListener() {
        @Override
        public void onAnrHappened(String stackTraceInfo) {
            Log.i(TAG, "OnAnrHappened: ======= ANR:"+ stackTraceInfo); }}); ANRWatchDog.getInstance().start();// In the simulation scenario, the handler sends the message to sleep for 10 seconds, and the detection tool of ANR will detect that the message sent by itself has not been processed for more than 5s, and "ANR" has occurred.
    handler.postDelayed(new Runnable() {
        @Override
        public void run(a) {
            try {
                Thread.sleep(1000 * 10);
            } catch(InterruptedException e) { e.printStackTrace(); }}},3000);

}
Copy the code

How do I analyze ANR files

Analysis of ANR is widely available online, and ANR can be largely avoided by paying attention to scenarios in which ANR is likely to occur. There are several common patterns to consider when diagnosing ANR:

  1. Applications perform I/O operations very slowly on the main thread.
  2. Application in the main thread long time calculation.
  3. The main thread is making a synchronous binder call to another process that takes a long time to return.
  4. The main thread is blocked, waiting for synchronized blocks for long operations that take place on another thread.
  5. The main thread deadlocks with another thread in a process or through a binder call. The main thread is not only waiting for the long operation to complete, it is in a deadlock state. For more information, see Deadlocks on Wikipedia.

For specific ANR file analysis and solutions, refer to the official website and this article

conclusion

For ANR analysis, this paper did not carefully into the source code (if you want to see some of ANR source code analysis can view gityuan column article), but did a lot of code practice came to the conclusion that, of course, I also see the source code verification again, see the source code is important, but if you just stop looking at the source, You may not get all of these scenarios right. Hope this article helps you, give it a thumbs up if you like.

Refer to the article

Gityuan.com/2016/07/02/…

Gityuan.com/2019/04/06/…

My.oschina.net/u/920274/bl…

Blog.csdn.net/lusing/arti…

Juejin. Cn/post / 684490…