Some of our users are experiencing an ANR on startup. Looking at the reports in Play Store it looks like it happens when our app calls:
NsdManager nsdManager = (NsdManager)context.getSystemService(Context.NSD_SERVICE);
Reading the docs I don't understand how this could fail.
Once in this mode the app will not launch until the handset has been restarted. I have only managed to reproduce the problem once, but while it is happening Logcat is reporting errors from NsdService
E/NsdService: Failed to execute mdnssd [stop-discover, 0]
com.android.server.NativeDaemonTimeoutException: command '709 mdnssd stop-discover 0' failed with 'null'
at com.android.server.NativeDaemonConnector.executeForList(NativeDaemonConnector.java:490)
at com.android.server.NativeDaemonConnector.execute(NativeDaemonConnector.java:401)
at com.android.server.NativeDaemonConnector.execute(NativeDaemonConnector.java:396)
at com.android.server.NsdService$DaemonConnection.execute(NsdService.java:698)
at com.android.server.NsdService.stopServiceDiscovery(NsdService.java:743)
at com.android.server.NsdService.-wrap7(Unknown Source:0)
at com.android.server.NsdService$NsdStateMachine$EnabledState.processMessage(NsdService.java:305)
at com.android.internal.util.StateMachine$SmHandler.processMsg(StateMachine.java:992)
at com.android.internal.util.StateMachine$SmHandler.handleMessage(StateMachine.java:809)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:164)
at android.os.HandlerThread.run(HandlerThread.java:65)
Which makes it look to me like the NSD system service itself is not in a good state.
My question is how could I have put NsdService in this state and, secondly, how can I recover it?
The reports on Play Store are only on Android 8 and 8.1 if that helps and the log gives the following:
"main" prio=5 tid=1 Waiting
| group="main" sCount=1 dsCount=0 flags=1 obj=0x74bcaed8 self=0x7b162c0a00
| sysTid=6277 nice=0 cgrp=default sched=0/0 handle=0x7b1b9c99c8
| state=S schedstat=( 90600226 20695151 166 ) utm=4 stm=4 core=5 HZ=100
| stack=0x7fc55c0000-0x7fc55c2000 stackSize=8MB
| held mutexes=
at java.lang.Object.wait (Native method)
- waiting on <0x0aad0ffc> (a java.lang.Object)
at java.lang.Thread.parkFor$ (Thread.java:2135)
- locked <0x0aad0ffc> (a java.lang.Object)
at sun.misc.Unsafe.park (Unsafe.java:358)
at java.util.concurrent.locks.LockSupport.park (LockSupport.java:190)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt (AbstractQueuedSynchronizer.java:868)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly (AbstractQueuedSynchronizer.java:1021)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly (AbstractQueuedSynchronizer.java:1328)
at java.util.concurrent.CountDownLatch.await (CountDownLatch.java:232)
at android.net.nsd.NsdManager.init (NsdManager.java:477)
at android.net.nsd.NsdManager.<init> (NsdManager.java:267)
at android.app.SystemServiceRegistry$33.createService (SystemServiceRegistry.java:573)
at android.app.SystemServiceRegistry$33.createService (SystemServiceRegistry.java:569)
at android.app.SystemServiceRegistry$CachedServiceFetcher.getService (SystemServiceRegistry.java:1374)
- locked <0x0f76c685> (a java.lang.Object[])
at android.app.SystemServiceRegistry.getSystemService (SystemServiceRegistry.java:1326)
at android.app.ContextImpl.getSystemService (ContextImpl.java:1695)
at android.content.ContextWrapper.getSystemService (ContextWrapper.java:727)
Solved.
The code which uses the NsdService is shared between 2 activities. Since both need to make sure it is running when they need it, it is possible that both activities try to start it in quick succession. Since the code tried to stop the service if it was running before starting it, this lead to a rapid start-stop-start that left the NsdService in a broken state (at least for our app).
The solution is to introduce some state to avoid restarting an already running service.