Introduce ANR

ANR, which is short for “Application Not Responding,” or “Application Not Responding.” A dialog box is presented to the user, and the user can choose to “wait” and let the program continue, or “force shutdown.”

ANR condition occurs

  • Events that do not respond to input within 5 seconds (e.g. key press, screen touch)
  • The BroadcastReceiver did not finish executing for 10 seconds
  • The Service could not complete processing for a specific period of time (20 seconds)

ANR can be caused by time-consuming operations on the main thread, such as network connections, I/O reads and writes, and thread synchronization locks. Note that this ANR is generated only when there is an input event. If the user does not trigger any input event, the ANR will not be generated even if the main thread is blocked.

Take a look at some sample code

public class AnrActivity extends Activity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.content_main);

        start();
    }
    private synchronized void start(a) {
        try {
            while (true) {
                Thread.sleep(10000); }}catch(InterruptedException e) { e.printStackTrace(); }}}Copy the code
  • Does ANR occur at startup? No, because there are no input events
  • Will ANR occur when you hit the back button? will

How do I obtain ANR logs

Old version system

  • ANR logs are stored in data/ ANR/localted.txt

  • adb shell cat /data/anr/traces.txt > /… / localted. TXT can export log files

New Version system

  • /data/anr/ localted. TXT /data/anr/ localted. TXT /data/anr/ localted. TXT /data/anr/ localted. TXT
  • Use ADB bugreport <zip_file> to generate a zip file named zip_file in the computer’s current directory

Analyze ANR logs

  • The process ID, time, and process name for the first two lines of ANR.
----- pid 24277 at 2019-09-16 16:23:19 -----
Cmd line: com.example.androidtest
Copy the code
  • Information such as memory
Build fingerprint: 'Google/walleye/walleye: 9 / PQ1A 190105.004/5148680: user/release - keys'
ABI: 'arm64'
Build type: optimized
Zygote loaded classes=10643 post zygote classes=81
Intern table: 73306 strong; 365 weak
JNI: CheckJNI is on; globals=602 (plus 23 weak)
Libraries: /system/lib64/libandroid.so /system/lib64/libcompiler_rt.so /system/lib64/libjavacrypto.so /system/lib64/libjnigraphics.so /system/lib64/libmedia_jni.so /system/lib64/libsoundpool.so /system/lib64/libwebviewchromium_loader.so libjavacore.so libopenjdk.so (9)
Heap: 33% free, 1760KB/2MB; 42897 objects
......
suspend all histogram:	Sum: 133us 99% C.I. 1us-46us Avg: 8.866us Max: 46us
Copy the code
  • Specific thread information
"Signal Catcher" daemon prio=5 tid=3 Runnable | group="system" sCount=0 dsCount=0 flags=0 obj=0x13dc0000 self=0x78a0a16400 | sysTid=24283 nice=0 cgrp=default sched=0/0 handle=0x789a1ff4f0 | state=R schedstat=( 11415990 257604  4 ) utm=0 stm=0 core=6 HZ=100 | stack=0x789a104000-0x789a106000 stackSize=1009KB | held mutexes= "mutator lock"(shared held) native: #00 pc 00000000003c7324 /system/lib64/libart.so (art::DumpNativeStack(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, int, BacktraceMap*, char const*, art::ArtMethod*, void*, bool)+220) native: #01 pc 0000000000495d80 /system/lib64/libart.so (art::Thread::DumpStack(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, bool, BacktraceMap*, bool) const+352) native: #02 pc 00000000004afd1c /system/lib64/libart.so (art::DumpCheckpoint::Run(art::Thread*)+844) native: #03 pc 00000000004a8a5c /system/lib64/libart.so (art::ThreadList::RunCheckpoint(art::Closure*, art::Closure*)+476) native: #04 pc 00000000004a7eac /system/lib64/libart.so (art::ThreadList::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char>>&, bool)+1036) native: #05 pc 00000000004a79b4 /system/lib64/libart.so (art::ThreadList::DumpForSigQuit(std::__1::basic_ostream<char, std::__1::char_traits<char>>&)+884) native: #06 pc 0000000000477864 /system/lib64/libart.so (art::Runtime::DumpForSigQuit(std::__1::basic_ostream<char, std::__1::char_traits<char>>&)+188) native: #07 pc 000000000048372c /system/lib64/libart.so (art::SignalCatcher::HandleSigQuit()+1372) native: #08 pc 0000000000482420 /system/lib64/libart.so (art::SignalCatcher::Run(void*)+256) native: #09 pc 0000000000083194 /system/lib64/libc.so (__pthread_start(void*)+36) native: #10 pc 00000000000233bc /system/lib64/libc.so (__start_thread+68) (no managed stack frames)Copy the code

instructions

  • The first line

Thread name (daemons if present)

Prio: indicates the priority of a thread

Dar: thread number

The current status of the thread Runnable

  • The second line

Group: indicates the thread group to which the thread belongs

SCount: indicates the number of times the thread is suspended

DsCount: The number of times the thread is suspended for debugging

Obj: Java thread object associated with the current thread

Self: address of the current thread

  • The third line

SysTid: the tid of a thread

Nice: scheduling priority A smaller nice value indicates a higher priority

CGRP: scheduling group to which a thread belongs

Sched: scheduling policy

Handle: address of function processing

  • In the fourth row

State: indicates the status of the thread

Schedstat: CPU scheduling time statistics

The three numbers in the schedstat brackets are Running, Runable, Switch,

  • Running time: indicates the CPU Running time, in ns
  • Runable time: wait time of the RQ queue, in ns
  • Switch times: indicates the number of CPU scheduling switches

Utm/STM: CPU time in user/kernel mode

Utm: time for the thread to execute in user mode, in jiffies. Jiffies are defined as sysconf(_SC_CLK_TCK), and the default value is 10ms.

STM: the time for the thread to execute in kernel mode, in jiffies. The default value is 10ms.

Utm + STM = schedstat first parameter value.

Core: the core in which the thread was last run

HZ: clock frequency

  • The fifth row

Stack: address range of the thread stack

StackSize: indicates the stackSize

  • The sixth line

Mutex: The muTEX type is exclusive and shared

Analyze ANR logs

Start by simulating a code that causes ANR

public class AnrActivity extends Activity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.content_main);

        findViewById(R.id.txt).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) { stop(); }});new Thread(new Runnable() {
            @Override
            public void run(a) {
                start();
            }
        }).start();
    }

    private synchronized void start(a) {
        long startTime = System.currentTimeMillis();
        while (true) {
            long stopTime = System.currentTimeMillis();
            if ((stopTime - startTime) / 1000> =10) {
                break; }}}private synchronized void stop(a) {
        Toast.makeText(AnrActivity.this."stop", Toast.LENGTH_SHORT).show(); }}Copy the code
"main" prio=5 tid=1 Blocked
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x75586910 self=0x78a0a14c00
  | sysTid=24277 nice=-10 cgrp=default sched=0/0 handle=0x79264f2548
  | state=S schedstat=( 289217601 7166871 217 ) utm=25 stm=3 core=6 HZ=100
  | stack=0x7fe93cd000-0x7fe93cf000 stackSize=8MB
  | held mutexes=
  at com.example.androidtest.anr.AnrActivity.stop(AnrActivity.java:-1)
  - waiting to lock <0x06b3ced2> (a com.example.androidtest.anr.AnrActivity) held by thread 13
  at com.example.androidtest.anr.AnrActivity.access$000(AnrActivity.java:12)
  at com.example.androidtest.anr.AnrActivity$1.onClick(AnrActivity.java:21)
  at android.view.View.performClick(View.java:6597)
  at android.view.View.performClickInternal(View.java:6574)
  at android.view.View.access$3100(View.java:778)
  at android.view.View$PerformClick.run(View.java:25885)
  at android.os.Handler.handleCallback(Handler.java:873)
  at android.os.Handler.dispatchMessage(Handler.java:99)
  at android.os.Looper.loop(Looper.java:193)
  at android.app.ActivityThread.main(ActivityThread.java:6718)
  at java.lang.reflect.Method.invoke(Native method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Copy the code
  • “Main” prio=5 TID =1 Blocked The main thread is Blocked
  • By mutexes = at com. Example. Androidtest. Anr. AnrActivity. Stop (AnrActivity. Java: 1) anr in stop method
  • Waiting to lock < 0 x06b3ced2 > (a com. Example. Androidtest. Anr. AnrActivity) by 13 in the thread by thread lock 13 < 0 x06b3ced2 > and wait

We know that tid stands for thread ID, so find information about the thread where tid=13

"Thread-2" prio=5 tid=13 Suspended
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x12c7ae18 self=0x78a0af1800
  | sysTid=24295 nice=0 cgrp=default sched=0/0 handle=0x788a5ff4f0
  | state=S schedstat=( 7380427077 3743221 140 ) utm=737 stm=0 core=5 HZ=100
  | stack=0x788a4fc000-0x788a4fe000 stackSize=1041KB
  | held mutexes=
  at com.example.androidtest.anr.AnrActivity.start(AnrActivity.java:35)
  - locked <0x06b3ced2> (a com.example.androidtest.anr.AnrActivity)
  at com.example.androidtest.anr.AnrActivity.access$100(AnrActivity.java:12)
  at com.example.androidtest.anr.AnrActivity$2.run(AnrActivity.java:27)
  at java.lang.Thread.run(Thread.java:764)
Copy the code

<0x06b3ced2> is locked in the start method.