An overview,

Recently, I encountered ANR in online projects, and summarized some experience in the process of solving the problem, which is summarized here.

  1. First of all, we need to understand what ANR is, what is the mechanism by which it occurs in the system, and why it occurs
  2. The second is how to solve ANR. Solving ANR has always been an important skill for Android developers to master, generally starting from three aspects.
    • Development stage: use tools to check the time consuming and lag of each method, and discover and modify one by one.
    • Online stage: This stage mainly relies on monitoring tools to discover and report ANR, such as Matrix.
    • Analysis phase: If an ONLINE user has ANR and you get a log. This is a common maintenance project, will focus on the ANR log analysis skills.

Ii. ANR generation mechanism

ANR full name: Application Not Responding.

On Android, ActivityManagerService(AMS) and WindowManagerService(WMS) detect the App’s response time. If the App is unable to respond to screen touch or keyboard input at a specific time, Or an ANR occurs when a particular event is not processed.

There are four types of ANR:

2.1 InputEvent Timeout: InputEvent times out (5s)

  1. InputDispatcher sends Key events to the Focused Window of the process. ANR occurs when the Focused Window does not exist, is suspended, input channel is full, channel is not registered, channel is abnormal, or no event is processed within 5 seconds
  2. InputDispatcher sends MotionEvent with one exception: If the Touched Window’s input waitQueue contains an event for more than 0.5 seconds, the inputDispatcher will pause the event and wait for 5 seconds. If the Window’s “Finish” event is not received, the ANR will be triggered
  3. ANR is triggered when the next event arrives and a timeout event is found
Example:

Create a Button and sleep for 10 seconds during the click event to block the main thread as follows.

findViewById<Button>(R.id.btn1).setOnClickListener {
    SystemClock.sleep(10 * 1000);
}
Copy the code

After clicking Button and then clicking back Button, ANR of “no response” can be triggered after a few seconds.

View the log information as follows

01-13 16:32:26.823 1580-1594/system_process I/Process: Sending Signal. PID: 1678 SIG: 3-13 16:32:26. 01, 824, 1678-1686 / com. Android. The systemui I/art: Thread[2,tid=1686,WaitingInMainSignalCatcherLoop,Thread*=0xae3c2000,peer=0x12c2d0a0,"Signal Catcher"]: 31 D/System_Process I/ Art: 31 D/D Demonstrate the stack traces to '/ data/anr/traces. TXT' 01-13 16:32:26. 972, 1678-1686 / com. Android. The systemui I/art: Wrote stack traces to '/data/anr/traces.txt'Copy the code

In the data/anr directory, export trace. TXT. You can find the following information in the log

1. "main" prio=5 tid=1 Sleeping
2.   | group="main" sCount=1 dsCount=0 obj=0x74088258 self=0xb4034500
3.   | sysTid=2686 nice=0 cgrp=default sched=0/0 handle=0xb770ac00
4.   | state=S schedstat=( 0 0 0 ) utm=21 stm=1 core=1 HZ=100
5.   | stack=0xbf678000-0xbf67a000 stackSize=8MB
6.   | held mutexes=
7.at java.lang.Thread.sleep! (Native method)8.   - sleeping on <0x0b4cba68> (a java.lang.Object)
9.   at java.lang.Thread.sleep(Thread.java:1031)
10.   - locked <0x0b4cba68> (a java.lang.Object)
11.   at java.lang.Thread.sleep(Thread.java:985)
12.   at com.example.kotlintest.MainActivity$onCreate$1.onClick(MainActivity.kt:14)
13.   at android.view.View.performClick(View.java:5198)
14.   at android.view.View$PerformClick.run(View.java:21147)
15.   at android.os.Handler.handleCallback(Handler.java:739)
16.   at android.os.Handler.dispatchMessage(Handler.java:95)
17.   at android.os.Looper.loop(Looper.java:148)
18.   at android.app.ActivityThread.main(ActivityThread.java:5417)
19.at java.lang.reflect.Method.invoke! (Native method)20.   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
21.   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Copy the code

Lines 7-12 indicate where and why ANR is occurring, and line 1 indicates that the main thread is Sleeping.

2.2 BroadcastTimeout Broadcast type Timeout (foreground 15s, background 60s)

BroadcastReceiver onReceiver Broadcasts transactions in the foreground within 15 seconds and in the background within 60 seconds. ANR occurred without processing completion

  1. Statically registered and ordered broadcasts are ANR, dynamically registered and unordered broadcasts are not ANR
  2. When a broadcast is sent, the system checks whether the process exists. If the process does not exist, it is created. The process creation time is counted in the timeout period
  3. The ANR dialog box will be displayed only when the process has a foreground Activity. Otherwise, the ANR dialog box will be killed
  4. When onReceive execution exceeds the threshold (foreground 15s, background 60s), ANR is generated
  5. Intent.addflags (intent.flag_receiver_foreground)

Ex. :

/ / create a Receiver
class ANRReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Toast.makeText(context, "start", Toast.LENGTH_SHORT).show()
        SystemClock.sleep(15 * 1000)
        Toast.makeText(context, "end", Toast.LENGTH_SHORT).show()
    }
}

Copy the code
/ / AndroidManifest. XML is registered
<receiver android:name=".ANRReceiver">
</receiver>
Copy the code
// Send an explicit broadcast
findViewById<Button>(R.id.anr_broadcast_btn).setOnClickListener {
    val intent = Intent()
    intent.component = ComponentName(this, ANRReceiver::class.java)
    intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND)   // Use foreground broadcast here, easier to test
    sendBroadcast(intent)
}
Copy the code

/ data/anr/trace. TXT log

"main" prio=5 tid=1 Sleeping
  | group="main" sCount=1 dsCount=0 obj=0x74088258 self=0xb4034500
  | sysTid=3918 nice=0 cgrp=default sched=0/0 handle=0xb770ac00
  | state=S schedstat=( 0 0 0 ) utm=12 stm=4 core=0 HZ=100
  | stack=0xbf678000-0xbf67a000stackSize=8MB | held mutexes= at java.lang.Thread.sleep! (Native method) - sleeping on <0x0c9a235a> (a java.lang.Object)
  at java.lang.Thread.sleep(Thread.java:1031)
  - locked <0x0c9a235a> (a java.lang.Object)
  at java.lang.Thread.sleep(Thread.java:985)
  at android.os.SystemClock.sleep(SystemClock.java:120)
  at com.example.kotlintest.ANRReceiver.onReceive(ANRReceiver.kt:12)
  at android.app.ActivityThread.handleReceiver(ActivityThread.java:2725)
  at android.app.ActivityThread.-wrap14(ActivityThread.java:-1)
  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1421)
  at android.os.Handler.dispatchMessage(Handler.java:102)
  at android.os.Looper.loop(Looper.java:148)
  at android.app.ActivityThread.main(ActivityThread.java:5417) at java.lang.reflect.Method.invoke! (Native method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Copy the code

2.3 ServiceTimeout The service times out (foreground 20 seconds, background 200 seconds)

Bind,create,start,unbind, etc. The ANR occurs when the foreground Service does not complete the process within 20 seconds and the background Service does not complete the process within 200 seconds

  1. The following methods of the Service trigger ANR: onCreate(),onStartCommand(), onStart(), onBind(), onRebind(), onTaskRemoved(), onUnbind(), onDestroy().
  2. The foreground Service timeout duration is 20 seconds, and the background Service timeout duration is 200 seconds
  3. How to distinguish foreground from Background execution ———— The APP is in user mode, and the Service executed in this case is foreground execution.
  4. User state: Foreground Activity, foreground broadcast, foreground Service executed

Ex. :

/ / create the Service
class ANRService : Service() {

    private val TAG = "ANRService"

    override fun onCreate(a) {
        super.onCreate()
        Log.i(TAG, "onCreate: ANRService start")
        SystemClock.sleep(20 * 1000)
        Log.i(TAG, "onCreate: ANRService end")}override fun onBind(intent: Intent?).: IBinder? {
        TODO("Not yet implemented")}}/ / registration service
<service android:name=".ANRService" />

// Add button event to start Service
findViewById<Button>(R.id.anr_service_btn).setOnClickListener {
    val intent = Intent()
    intent.component = ComponentName(this, ANRService::class.java)
    startService(intent)
}
Copy the code

/ data/anr/trace. TXT log

"main" prio=5 tid=1 Sleeping
  | group="main" sCount=1 dsCount=0 obj=0x74088258 self=0xb40b4500
  | sysTid=3750 nice=0 cgrp=default sched=0/0 handle=0xb7777c00
  | state=S schedstat=( 0 0 0 ) utm=14 stm=1 core=0 HZ=100
  | stack=0xbf067000-0xbf069000stackSize=8MB | held mutexes= at java.lang.Thread.sleep! (Native method) - sleeping on <0x0adfdbe3> (a java.lang.Object)
  at java.lang.Thread.sleep(Thread.java:1031)
  - locked <0x0adfdbe3> (a java.lang.Object)
  at java.lang.Thread.sleep(Thread.java:985)
  at android.os.SystemClock.sleep(SystemClock.java:120)
  at com.hjc.aartest.ANRService.onCreate(ANRService.kt:16)
  at android.app.ActivityThread.handleCreateService(ActivityThread.java:2877)
  at android.app.ActivityThread.-wrap4(ActivityThread.java:-1)
  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1427)
  at android.os.Handler.dispatchMessage(Handler.java:102)
  at android.os.Looper.loop(Looper.java:148)
  at android.app.ActivityThread.main(ActivityThread.java:5417) at java.lang.reflect.Method.invoke! (Native method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Copy the code

2.4 ProcessContentProviderPublishTimedOutLocked: ContentProvider publish no processing is completed within 10 s

  1. ContentProvider create publish timeout does not ANR
  2. Use ContentProviderclient to visit ContentProverder can choose on their own will trigger ANR, timeout your client. SetDetectNotResponding (PROVIDER_ANR_TIMEOUT);

2.5 PS:

Does the Activity life cycle time out cause ANR? It didn’t work, but the interface stuck. However, if a keystroke is performed during a delay, the input event will timeout.

override fun onCreate(savedInstanceState: Bundle?). {
    Thread.sleep(60000) 
    super.onCreate(savedInstanceState) 
    setContentView(R.layout.activity_main) 
}
Copy the code

Iii. Causes of ANR

Many developers believe that ANR is caused by time-consuming operations, and that it is all app layer problems. In fact, most of the ANR in the online environment is due to system reasons.

ANR caused by application layer (time-consuming operation)

  1. Function blocking: such as infinite loop, main thread IO, processing big data
  2. Lock error: the main thread waits for the lock of the child thread
  3. Memory shortage: The memory allocated by the system to an application has an upper limit. If the memory is in shortage for a long time, memory swapping will occur frequently and some operations of applications will time out

The system causes ANR

  1. CPU grab: Generally speaking, the foreground is playing a game, which may cause your background broadcast to be CPU grab
  2. System services cannot respond in a timely manner: For example, obtaining system contacts, the system services are all Binder mechanisms with limited service capabilities. ANR may occur if the system services do not respond for a long time
  3. Other applications take up a lot of memory

Thank you for the article

  • Dry: ANR log analysis comprehensive analysis
  • Android ANR: Principle analysis and solutions