For the first time to read dry goods, you can pay attention to my public number: program ape cultivation center

I. ANR description and reasons

1.1 introduction

ANR full name: Application Not Responding.

1.2 the reason

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.

ANR can occur under the following four conditions:

  • InputDispatching Timeout: Failed to respond to the screen touch event or keyboard input event within 5 seconds
  • BroadcastQueue Timeout: in the implementation of the BroadcastReceiveronReceive()Function for 10 seconds without completion of processing, background for 60 seconds.
  • Service Timeout: indicates that the foreground Service is not executed within 200 seconds.
  • ContentProvider Timeout: The ContentProvider publish is not complete within 10 seconds.

1.3 to avoid

Try to avoid time-consuming operations in the main thread (UI thread).

Time-consuming operations are placed in child threads. For more information about multithreading, see: Android Multithreading: Summary of understanding and simple use

ANR analysis method

2.1 ANR reproduce

A button is generated to jump to ANRTestActivity, where the main thread sleeps for 20 seconds in onCreate() :

@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_anr_test); // This is the Thread sleep function provided by Android, which differs from Thread.sleep() in that it does not throw InterruptedException. SystemClock.sleep(20 * 1000); }Copy the code

After entering ANRTestActivity, there was a black screen for about seven or eight seconds before an ANR exception popped up.

2.2 ANR analysis method 1: Log

After generating ANR just now, look at Log:

Can see logcat clearly recorded the time of ANR happen, as well as thread dar and brief reasons: WaitingInMainSignalCatcherLoop, give priority to the thread waiting to be abnormal. The application may be doing too much work on its main thread. Notification may be doing too much work on the main thread.

2.3 ANR analysis method 2: tracte.txt

1. “/data/anr/ tettl. TXT”; 2. “/data/anr/ tettl. TXT”; 3.

  1. CDS toadb.exeThe directory in which it is located, which isAndroid SDKtheplatform-toolsContents, for example:
cd D:\Android\AndroidSdk\platform-tools

Copy the code

In addition to the CMD for Windows, you can also use the Terminal for AndroidStudio to enter ADB commands.

  1. Go to the specified directory and run the following ADB command to exporttraces.txtFile:
adb pull /data/anr/traces.txt

Copy the code

Tetrace.txt is exported to the ** * platform-tools** directory of the Android SDK by default. In general, the testamp.txt file will contain a lot of things, so you need to find relevant records when analyzing them.

----- pid 23346 at 2017-11-07 11:33:57 ----- ----> Process ID and ANR generation time Cmd line: com.sky.myjavatest Build fingerprint: 'Google/marlin/marlin: 8.0.0 / OPR3.170623.007/4286350: user/release - keys' ABI:' arm64 Build type: optimized Zygote loaded classes=4681 post zygote classes=106 Intern table: 42675 strong; 137 weak JNI: CheckJNI is on; globals=526 (plus 22 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: 22% free, 1478KB/1896KB; 21881 objects ----> Memory usage... "Main" prio = 5 tid = 1 Sleeping -- -- -- -- > reason for Sleeping | group = "main" sCount = 1 dsCount obj = 0 x733d0670 = 0 flags = 1 self=0x74a4abea00 | sysTid=23346 nice=-10 cgrp=default sched=0/0 handle=0x74a91ab9b0 | state=S schedstat=( 391462128 82838177 354 ) utm=33 stm=4 core=3 HZ=100 | stack=0x7fe6fac000-0x7fe6fae000 stackSize=8MB | held mutexes= at java.lang.Thread.sleep(Native method) - sleeping on <0x053fd2c2> (a java.lang.Object) at java.lang.Thread.sleep(Thread.java:373) - locked <0x053fd2c2> (a java.lang.Object) at java.lang.Thread.sleep(Thread.java:314) at android.os.SystemClock.sleep(SystemClock.java:122) at Com. Sky. Myjavatest. ANRTestActivity. OnCreate (20) ANRTestActivity. Java: -- -- -- - > generate ANR package name and the specific number of rows at android.app.Activity.performCreate(Activity.java:6975) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892) at android.app.ActivityThread.-wrap11(ActivityThread.java:-1) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593) at android.os.Handler.dispatchMessage(Handler.java:105) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6541) at java.lang.reflect.Method.invoke(Native method) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)Copy the code

Use CTRL + F to find the package name in the file to quickly locate the relevant code. Related problems can be seen from the above log:

  • Process ID and package name:pid 23346 com.sky.myjavatest
  • Causes of ANR:Sleeping
  • The exact number of rows resulting in ANR:ANRTestActivity.java:20Class on line 20

Note that the original testamp.txt file will be overwritten when new ANR is generated.

2.4 ANR Analysis method 3: Java thread call analysis

You can use the following commands provided by the JDK to analyze and debug Java applications:

jstack {pid}

Copy the code

Pid can be obtained from the JPS command, which lists all Java virtual machine processes running in the current system, for example

7266 Test
7267 Jps

Copy the code

Specific analysis reference: Android application ANR analysis iv.1

2.5 ANR Analysis Method 4: ANALYZE ANR problems by DDMS

  • Use DDMS — Update Threads tool
  • Read the output of Update Threads

Specific analysis reference: Android application ANR analysis iv.2

Iii. Causes and solutions of ANR

The above example is only ANR caused by a simple main-thread time-consuming operation. There are many other reasons for ANR:

  • Main thread block or main thread data read

Solution: Avoid deadlocks and use child threads to handle time-consuming operations or blocking tasks. Avoid query providers in the main thread and don’t abuse SharePreferenceS

  • The CPU is full and I/O is blocked

Workaround: File reads and writes or database operations are placed in child thread asynchronous operations.

  • Out of memory

Androidmanifest.xml can set Android :largeHeap=”true” to increase the memory usage of the App. However, it is not recommended to use this method, to prevent memory leaks fundamentally, optimizing memory usage is the right way.

  • ANR of major components

It is also important to avoid time-consuming operations in the life cycle of BroadcastReciever’s onRecieve(), backend Services, and ContentProviders.

ANR source code analysis

The ANR is generated by Service, BroadcastReceiver, and ContentProvider. I use the code below and summarize it with my own simple understanding.

4.1 ServiceCaused by theService Timeout

Service Timeout is triggered when the ams. MainHandler in the **”ActivityManager”** thread receives a SERVICE_TIMEOUT_MSG message.

4.1.1 Sending A Delayed Message

Attach to the system_server Service process in the process of calls realStartServiceLocked, followed by a mAm. MHandler. SendMessageAtTime () to send a delayed message, delay often is defined, For example, 20 seconds for the foreground Service. Generated when ams.mainHandler in the ActivityManager thread receives a SERVICE_TIMEOUT_MSG message.

AS.realStartServiceLocked

ActiveServices.java

private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException { ... / / send delay messages (SERVICE_TIMEOUT_MSG) bumpServiceExecutingLocked (r, execInFg, "create"); try { ... / / final execution services onCreate () method of the app. The thread. ScheduleCreateService (r, r.s erviceInfo, mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo), app.repProcState); } catch (DeadObjectException e) { mAm.appDiedLocked(app); throw e; } finally { ... }}Copy the code

AS.bumpServiceExecutingLocked

private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) { ... scheduleServiceTimeoutLocked(r.app); } void scheduleServiceTimeoutLocked(ProcessRecord proc) { if (proc.executingServices.size() == 0 || proc.thread == null)  { return; } long now = SystemClock.uptimeMillis(); Message msg = mAm.mHandler.obtainMessage( ActivityManagerService.SERVICE_TIMEOUT_MSG); msg.obj = proc; / / when the Timeout after still didn't remove the SERVICE_TIMEOUT_MSG message, performs the service Timeout process mAm. MHandler. SendMessageAtTime (MSG, proc. ExecServicesFg? (now+SERVICE_TIMEOUT) : (now+ SERVICE_BACKGROUND_TIMEOUT)); }Copy the code

4.1.2 Enter the main thread of the target process to create a Service

The main thread of the target process is called through Binder and other layershandleCreateService(CreateServiceData data).

ActivityThread.java

private void handleCreateService(CreateServiceData data) { ... java.lang.ClassLoader cl = packageInfo.getClassLoader(); Service service = (Service) cl.loadClass(data.info.name).newInstance(); . Try {/ / create ContextImpl object ContextImpl context. = ContextImpl createAppContext (this, packageInfo); context.setOuterContext(service); / / create the Application object Application app = packageInfo makeApplication (false, mInstrumentation); service.attach(context, this, data.info.name, data.token, app, ActivityManagerNative.getDefault()); // Call the service onCreate() method service.oncreate (); / / cancel the AMS MainHandler ActivityManagerNative delay news. GetDefault () serviceDoneExecuting (data) token, SERVICE_DONE_EXECUTING_ANON, 0, 0); } catch (Exception e) { ... }}Copy the code

OnCreate () is a callback to the onCreate() method of the Service, and a serviceDoneExecuting() is a callback to system_server to cancel the delayed message of ams.mainHandler.

4.1.3 Return to system_server and cancel the delayed message of ams.mainHandler

AS.serviceDoneExecutingLocked

private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying, boolean finishing) { ... if (r.executeNesting <= 0) { if (r.app ! = null) { r.app.execServicesFg = false; r.app.executingServices.remove(r); If (of state Richard armitage pp. ExecutingServices. The size () = = 0) {/ / the current service without being performed in the process of service mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app); . }... }Copy the code

In this method, the delayed message SERVICE_TIMEOUT_MSG is removed when the Service logic is complete. If the method is not called until the execution is complete, SERVICE_TIMEOUT_MSG will be issued after the timeout to inform ANR of the occurrence.

4.2 BroadcastReceiverThe BroadcastQueue Timeout result is displayed

BroadcastReceiver Timeout is located in * * * * “ActivityManager” thread of BroadcastQueue. Trigger BROADCAST_TIMEOUT_MSG BroadcastHandler received the news.

4.2.1 Processing broadcastTimeoutLocked(false) in processNextBroadcast() sends delayed messages

The broadcast processing sequence processes the parallel broadcast first, then the current ordered broadcast.

final void processNextBroadcast(boolean fromMsg) { synchronized(mService) { ... Do {r = mOrderedBroadcasts. Get (0); // Get all receivers of the broadcast int numReceivers = (R.extvers! = null) ? r.receivers.size() : 0; if (mService.mProcessesReady && r.dispatchTime > 0) { long now = SystemClock.uptimeMillis(); if ((numReceivers > 0) && (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) { //step 1\. BroadcastTimeoutLocked (false); broadcastTimeoutLocked(false); broadcastTimeoutLocked(false); . } } if (r.receivers == null || r.nextReceiver >= numReceivers || r.resultAbort || forceReceive) { if (r.resultTo ! = null) {//2\. Handle broadcast message performReceiveLocked(r.Allerapp, R.tesultto, new Intent(R.intent), r.tesultCode, r.resultData, r.resultExtras, false, false, r.userId); r.resultTo = null; } / / 3 \. Cancel the radio timeout ANR message cancelBroadcastTimeoutLocked (); } } while (r == null); . R.riceivertime = systemclock. uptimeMillis(); if (! mPendingBroadcastTimeoutMessage) { long timeoutTime = r.receiverTime + mTimeoutPeriod; / / set the timeout radio setBroadcastTimeoutLocked (timeoutTime); }... }}Copy the code

BroadcastTimeoutLocked (false) : calls broadcastTimeoutLocked(false) functions that record time information and set delay messages

final void broadcastTimeoutLocked(boolean fromMsg) {
    ...
        long now = SystemClock.uptimeMillis();
        if (fromMsg) {
            if (mService.mDidDexOpt) {
                // Delay timeouts until dexopt finishes.
                mService.mDidDexOpt = false;
                long timeoutTime = SystemClock.uptimeMillis() + mTimeoutPeriod;
                setBroadcastTimeoutLocked(timeoutTime);
                return;
            }
            if (!mService.mProcessesReady) {
                return;
            }

            long timeoutTime = r.receiverTime + mTimeoutPeriod;
            if (timeoutTime > now) {
                // step 2
                setBroadcastTimeoutLocked(timeoutTime);
                return;
            }
        }

Copy the code

Step 2 above. SetBroadcastTimeoutLocked function: set the timeout radio specific operation, the same delay message is sent

final void setBroadcastTimeoutLocked(long timeoutTime) { if (! mPendingBroadcastTimeoutMessage) { Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this); mHandler.sendMessageAtTime(msg, timeoutTime); mPendingBroadcastTimeoutMessage = true; }}Copy the code

TimeoutTime 4.2.2 setBroadcastTimeoutLocked (long timeoutTime) function of the parameters is the current time and set the timeout time.

That is, above

long timeoutTime = SystemClock.uptimeMillis() + mTimeoutPeriod;

Copy the code

The mTimeoutPeriod is 10s for the foreground queue and 60s for the background queue.

public ActivityManagerService(Context systemContext) { ... static final int BROADCAST_FG_TIMEOUT = 10 * 1000; static final int BROADCAST_BG_TIMEOUT = 60 * 1000; . mFgBroadcastQueue = new BroadcastQueue(this, mHandler, "foreground", BROADCAST_FG_TIMEOUT, false); mBgBroadcastQueue = new BroadcastQueue(this, mHandler, "background", BROADCAST_BG_TIMEOUT, true); . }Copy the code

Holdings in processNextBroadcast () procedure, after execution performReceiveLocked call cancelBroadcastTimeoutLocked

CancelBroadcastTimeoutLocked: Processing broadcast message function processNextBroadcast performReceiveLocked in () () finished processing broadcast messages, call cancelBroadcastTimeoutLocked cancel timeout messages ().

final void cancelBroadcastTimeoutLocked() { if (mPendingBroadcastTimeoutMessage) { mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this); mPendingBroadcastTimeoutMessage = false; }}Copy the code

4.3 ContentProvider的ContentProvider Timeout

ContentProvider Timeout is triggered when ams.mainHandler in the “ActivityManager” thread receives a CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG message. See section 4 to understand the triggering principles of Android ANR

5. Information collection of Android ANR

Whenever ANR occurs in any of the four major components, processes, etc., the ams.Appnotresponding () method is eventually called.

Finally, because the level is limited, have wrong place unavoidable, rather misdirect others, welcome big guy to correct! Code word is not easy, thank you for your attention!

🙏 If you are studying with me, you can follow my official account — ❤️ Program ape Development Center ❤️. Every week, we will share the technology of Android regularly.