"Summary" for Android platform engineers, ANR should be a problem for everyone, because there are many reasons for it, such as time-consuming operations on the main thread, calling a lot of CPU resources for complex budgeting, and possibly, in most cases, This kind of problem will not happen, only in the extreme special circumstances of exposure (such as a long time automated script testing, monkey testing), so we have to learn how to analyze such problems, in order to let the performance of the module can withstand the test.
I. What is ANR? Why does ANR happen?
If, after you have done something, you find a similar dialog on your phone screen, unfortunately, you have ...
anr,application Not responding, that is, the application is unresponsive. In General, when the application does not respond to user interaction, the system will pop up the above ANR dialog. This situation typically occurs when the main thread is blocked by the IO operation, and the main thread carries out a large number of operations such as reading the database. from the official Google documentation, the following two scenarios are the main causes:1. Application does not respond to user input events within 5 seconds2. Broadcastreceiver cannot complete the execution of OnReceive () method within 10 secondsNote: The above time is based on Google native code, many domestic manufacturers for some reasons will be extended, please use the specific vendor code
Two. Why does NFC occur with a ANR problem
First introduce NFC with a friend who has not contacted NFC.
nfc,near Field Communication, near-field communications, is a short-range radio technology evolved from contactless radio frequency identification (RFID) , developed jointly by Nokia, Sony and NXP. In foreign countries, such as Japan, this technology has been widely used, whether from travel to shopping, where there are FeliCa (Japan uses the NFC standard) figure. However, because of a treasure too strong and humane, NFC technology to promote any heavy and long way. But with applications such as Xiaomi wallets starting to use NFC to simulate bus cards and bank cards to facilitate the lives of users, individuals think that the future is beautiful!!!
As an important module of the local connectivity, NFC can not only carry Read/write Tag, but also transfer files via Android Beam (feature of Point-to-point transmissions that are supported by Android 4.0). Handover's function is to make NFC a fast link between WiFi and BT, which greatly facilitates the user's near-distance transmission. It is for these reasons that, in special cases, concurrent operations can cause problems with the ANR problem of the NFC, and the following is an analysis of the ANR cases caused by a simple NFC call to deadlock.
Three. Case studiesfirst recommend to you a view of the source code of the site, http://androidxref.com/, if there is no VPN, the site to see the source or comparison to force, probably most of the Buddies know, hehe ~
The following is a brief introduction to the actions that cause ANR to occur:in the case of NFC off, (Android beam must be turned off automatically as NFC is turned off, otherwise the Android beam option is not found in the share list because the corresponding component is disable), via Android Beam to share a file, this situation will pop up a hint need to turn on the NFC Function dialog, click OK, normally, will appear Android beam image zoom interface, such as, but the ANR occurs when the entire interface does not react, a few seconds later, The system will pop up settings Anr dialog.
for the analysis of the ANR problem, we should first find out when the problem occurs, the phone automatically saved in the Data/anr directory of the Trace.txt file, which is the most intuitive response to the problem occurs when the stack of information and the use of various resources.
Because Nfcservice is the most core of the NFC layer of the file, all the underlying processing will be a layer up to Nfcservice, the upper API interface will only be nfcservice to invoke the specific underlying implementation. All we now trace.txt in Nfcservice as the keyword to search, see the following trace.log
"Binder_1" prio=5 tid=8 Blocked (prio process number, TID thread number) | group= "main" scount=1 dscount=0 obj=0x12c8b0a0 self=0x7f8ef53400 | systid=2903 nice=0 cgrp=default sched=0/0 handle=0x7f93af5440 | State=s schedstat= (81420425 126587653 792) utm=3 stm=5 core=0 hz=100 | stack=0x7f939f9000-0x7f939fb000 stackSize=10 13KB | held mutexes= at com.android.nfc.nfcservice$nfcadapterservice.getstate (nfcservice.java:1813) - Waiting to lock <0x0196c7d2> (a Com.android.nfc.NfcService) held by thread---> blocked by thread 18 at Android.nfc.infcadapter$stub.ontransact (infcadapter.java:95) at android.os.Binder.execTransact (Binder.java : 477) </span>
From the above trace log can be seen, nfcservice$nfcadapterservice.getstate () want to get 0x0196c7d2, that is, Nfcservice object lock, the code is as follows
@Override public int getState () throws RemoteException { synchronized (nfcservice.this) { return mstate; } }
But this object lock is not immediately available because thread 18 is in use, looking at the stack information for thread 18
"Binder_3" prio=5 tid=18 Blocked | group= "main" scount=1 dscount=0 obj=0x12e120a0 self=0x7f94114200 | systid= 3414 nice=0 cgrp=default sched=0/0 handle=0x7f7c9a0440 | state=S schedstat=( 67563697 66692461 439 ) utm=0 stm=6 core= 0 hz=100 | stack=0x7f7c8a4000-0x7f7c8a6000 stacksize=1013kb | held mutexes= at Com.android.nfc.P2pLinkManager.isLlcpActive (p2plinkmanager.java:410) -Waiting to lock <0x0c8140a3> (a Com.android.nfc.P2pLinkManager) held by thread 1---> blocked at com.android.nfc.nfcservice$nxpextrasservice._ by threads 1 Open (nfcservice.java:3173) -locked <0x0196c7d2> (a com.android.nfc.NfcService) at Com.android.nfc.nfcservice$nxpextrasservice.open (nfcservice.java:3149) at com.nxp.intf.inxpextrasservice$ Stub.ontransact (inxpextrasservice.java:55) at android.os.Binder.execTransact (binder.java:477)
The above log shows that the Nfcservice object lock is being held by the Nfcservice$nxpextrasservice._open () method, and the code is as follows:
private int _open (IBinder b) { synchronized (nfcservice.this) { if (!isnfcenabled ()) { return ee_error_nfc_ DISABLED; } if (minprovisionmode) { //Deny access to the Nfcee as long as the device is being setup return ee_error_io; } if (Mp2plinkmanager.isllcpactive ()) { //Don ' t allow pn544-based devices to open the SE while the LLCP // Link is still up or in a debounce state. This avoids race //conditions in the NXP stack around p2p/smx switching. return Ee_error_ext_field; }
The above method is delayed execution, because the call to Mp2plinkmanager.isllcpactive (), this method wants to get 0x0c8140a3, that is, P2plinkmanager object lock, but this object lock can not be obtained immediately, is being suspended by Thread1.
public Boolean isllcpactive () { synchronized (this) {---> P2plinkmanager object lock return mlinkstate! = Link_state_ Down; } }
So let's continue to look at the trace information of Thread1:
"Main" prio=5 tid=1 Blocked | group= "main" scount=1 dscount=0 obj=0x762a8fb8 self=0x7f955fba00 | systid=2880 nice=0 cgrp=default sched=0/0 Handle=0x7f98da8fe8 | State=s schedstat= (344423025 553179190 922) utm=24 stm=10 core=3 hz=100 | stack=0x7fca15d000-0x7fca15f000 STACKSIZE=8MB | Held mutexes= at Com.android.nfc.NfcService.playSound (nfcservice.java:1509)-Waiting to lock <0x0196c7d2> (a COM. Android.nfc.NfcService) held by thread, at com.android.nfc.P2pEventManager.onP2pNfcTapRequested ( p2peventmanager.java:81) at Com.android.nfc.P2pLinkManager.onManualBeamInvoke (p2plinkmanager.java:455)-locked <0x0c8140a3> (a com.android.nfc.P2pLinkManager) at com.android.nfc.nfcservice$ Nfcservicehandler.handlemessage (nfcservice.java:4366) at Android.os.Handler.dispatchMessage (handler.java:102) at Android.os.Looper.loop (looper.java:148) at Android.app.ActivityThread.main (activitythread.java:5541) at java.lang.reflect.method.invoke! (Native method) at Com.android.interNal.os.zygoteinit$methodandargscaller.run (zygoteinit.java:935) at Com.android.internal.os.ZygoteInit.main ( zygoteinit.java:726)
0X0C8140A3 This lock is being occupied by the P2plinkmanager.onmanualbeaminvoke () method, the code is as follows:
public void Onmanualbeaminvoke (Beamsharedata sharedata) {synchronized (p2plinkmanager.this) {if (M Linkstate! = Link_state_down) {return; } if (Mforegroundutils.getforegrounduids (). Contains (Mndefcallbackuid)) {//Try to get the data from The registered NDEF callback Preparemessagetosend (FALSE); } else {mmessagetosend = null; Muristosend = null; } if (mmessagetosend = = NULL && Muristosend = = NULL && Sharedata! = null) {//N o data from the NDEF callback, get data from Sharedata if (sharedata.uris! = null) {MUr Istosend = Sharedata.uris; } else if (sharedata.ndefmessage! = null) {mmessagetosend = Sharedata.ndefmessage; } muserhandle = Sharedata.userhandle; } if (mmessagetosend! = NULL | | (Muristosend! = null && mhandoverdataparser.ishandoversupported ())) {msendstate = send_state_pending; Meventlistener.onp2pnfctaprequested (); Scheduletimeoutlocked (Msg_wait_for_link_timeout, Wait_for_link_timeout_ms); } } }
The above method will call Meventlistener.onp2pnfctaprequested (), the code is as follows:
@Override public void onp2pnfctaprequested () { mnfcservice.playsound (nfcservice.sound_start); Mndefsent = false; Mndefreceived = false; Mindebounce = false; Mvibrator.vibrate (Vibration_pattern,-1);
This method invokes the Mnfcservice.playsound () inside the nfcservice. Trace log shows that PlaySound () will want to hold 0X0196C7D2, which is Nfcservice object. See if the code is like this:
public void PlaySound (int. sound) { synchronized (this) {---> Nfcservice object lock if (Msoundpool = = null) { LOG.W (TAG, "not playing sound if NFC is disabled"); return; }
Please note here that the object being held by Nfcservice$nxpextrasservice._open () above is also this.
Now we basically know what the situation is, let's go back and get it over with.
Nfcadapterservice.getstate want to hold Nfcservice object, unable to get block
Nfcservice object is being held by Nxpextrasservice._open (), this method cannot be executed and is mp2plinkmanager.isllcpactive () block
Mp2plinkmanager.isllcpactive () Want to hold P2plinkmanager object, unable to get block
The P2plinkmanager object is being held by the Onmanualbeaminvoke () method, and this method cannot be executed and is meventlistener.onp2pnfctaprequested () block
Meventlistener.onp2pnfctaprequested () cannot be executed, Mnfcservice.playsound () block
Mnfcservice.playsound () wants to hold the Nfcservice object, which is held by the topmost Nxpextrasservice._open ()
So in general, the Nxpextrasservice._open () that is occupying Nfcservice locks requires P2plinkmanager lock release, The Onmanualbeaminvoke () method that is occupying P2plinkmanager this lock requires nfcservice lock release, and the two sides do not budge, causing a deadlock.
A temporary solution to the strategy is to
public void PlaySound (int sound) { synchronized (this) {<---> Nfcservice object lock if (Msoundpool = = null) { L OG.W (TAG, "not playing sound when NFC is disabled"); return; }
The range of the lock is reduced to a private lock.
That is, Object mplaysoundlock = new Obejct (), then replace this with Mplaysoundlock.
Note: My level is limited, you are welcome to criticize Daniel, thank you ~
Analysis of NFC problems caused by deadlock in ANR