我正在尝试在我公司的专有硬件设备上执行服务发现,该设备托管自己的 WiFi 网络并通过该网络宣传 bonjour 服务。当我连接到那个 WiFi 网络时,我正在使用 NSD 来发现该服务并解决它。
代码非常简单,通常运行良好且快速。除了我有一个相当反复出现的问题(大约 10 次尝试中的 5 次)到目前为止本地化到我的三星 S8+。目前无法在 S6 或 Pixel XL 上重现。
问题是 DiscoveryListener 除了 onDiscoveryStarted() 之外从不做任何事情,它只是永远运行。如果我杀死该应用程序并重新开始,有时它会工作,有时它会继续挂起。
就像有一个阻塞的线程或其他东西,但日志中没有有用的信息(我可以找到),而且我还没有找到任何东西可以锁定,因为我可以做些什么来从中恢复。
我添加了一个超时,它将在 30 秒后停止侦听器,但通常当我在那之后重试时它仍然不起作用。
服务发现过程包含在一个 LiveData 中,它在活动时启动它。
const val SERVICE_TYPE_FOO = "_foo._tcp."
private val serviceDiscoveryListener = ServiceDiscoveryListener()
override fun onActive() {
super.onActive()
stopRunnable = StopDiscoveryRunnable()
nsdManager.discoverServices(
SERVICE_TYPE_FOO,
NsdManager.PROTOCOL_DNS_SD,
serviceDiscoveryListener
)
handler.postDelayed(stopRunnable, SERVICE_DISCOVERY_TIMEOUT_MS)
}
private lateinit var stopRunnable: Runnable
private inner class StopDiscoveryRunnable : Runnable {
override fun run() {
try {
nsdManager.stopServiceDiscovery(serviceDiscoveryListener)
Timber.w("service discovery timed out")
postValue(ServiceDiscoveryState.Error)
} catch (e: Throwable) {
// no-op
}
}
}
听众很简单...
private inner class ServiceDiscoveryListener : NsdManager.DiscoveryListener {
override fun onServiceFound(serviceInfo: NsdServiceInfo?) {
if (serviceInfo != null) {
if (serviceInfo.serviceName.isNotEmpty() &&
serviceInfo.serviceName.containsFoo()
) {
nsdManager.resolveService(serviceInfo, ResolveListener())
handler.removeCallbacks(stopRunnable)
}
}
}
override fun onStopDiscoveryFailed(serviceType: String?, errorCode: Int) {
Timber.d("stop discovery failed")
nsdManager.stopServiceDiscovery(this)
postValue(ServiceDiscoveryState.Error)
}
override fun onStartDiscoveryFailed(serviceType: String?, errorCode: Int) {
Timber.d("start discovery failed")
nsdManager.stopServiceDiscovery(this)
postValue(ServiceDiscoveryState.Error)
}
override fun onDiscoveryStarted(serviceType: String?) {
Timber.d("discovery started")
}
override fun onDiscoveryStopped(serviceType: String?) {
Timber.d("discovery stopped")
}
override fun onServiceLost(serviceInfo: NsdServiceInfo?) {
Timber.d("discovery service lost")
postValue(ServiceDiscoveryState.Error)
}
}
private inner class ResolveListener : NsdManager.ResolveListener {
override fun onResolveFailed(serviceInfo: NsdServiceInfo?, errorCode: Int) {
Timber.d("resolve failed. errorCode = $errorCode")
if (errorCode != NsdManager.FAILURE_ALREADY_ACTIVE) {
Timber.d("not already active, so error")
postValue(ServiceDiscoveryState.Error)
} else {
Timber.d("already active")
}
}
override fun onServiceResolved(serviceInfo: NsdServiceInfo?) {
if (serviceInfo != null) {
Timber.d("resolved service: ${serviceInfo.serviceName} host: ${serviceInfo.host}:${serviceInfo.port} type: ${serviceInfo.serviceType}")
postValue(ServiceDiscoveryState.FooService(serviceInfo))
}
}
}
我无法在日志中找到太多有价值的东西,尽管当事情不工作时我确实看到了这条消息。试图寻找有关这个问题的答案的尝试并没有取得成果。
04-26 13:50:14.541 953-1218/? W//system/bin/netd:使用无效的 DNSServiceRef 0x72bb818000 FFFFFFFF DDDDDDDD 调用 dnssd_clientstub DNSServiceProcessResult
我还能提供哪些其他信息?
我已经在我的 S8+ 上使用 Andriy Druk 的 bonjour服务浏览器示例代码重现了这个问题,它甚至不使用 NSD ......所以看起来问题可能出在核心 mDNS 代码中,而不是特定于 Google 的 NSD 实现?
S8+ 上是否有一些系统软件或膨胀软件可能会干扰我对 NSD 或 mDNS 的使用 - 线程阻塞或其他什么?