Android : 在父进程突然退出后 运行 停止 Bonjour 服务
Android : Stopping a Bonjour service left running after the parent process quit abrubtly
我的应用程序本质上是一个后台服务,需要偶尔注册一个 NSD
服务(Bonjour
服务),以便主程序能够发现套接字服务器 运行后台服务(应用又名 运行)。
如果我没看错 Android Bonjour Service doc,这就是启动 Bonjour
服务的方式(为简洁起见缩写):
mNsdManager = Context.getSystemService(Context.NSD_SERVICE);
mDiscoveryListener = new NsdManager.DiscoveryListener()
mNsdManager.discoverServices(
SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
...这就是你如何阻止它:
mNsdManager.unregisterService(mRegistrationListener);
这是我无法理解的部分:如果主要服务突然关闭,崩溃时注册的任何 Bonjour
服务都会保持 运行ning,即使它不再有目的(它帮助发现的套接字服务器不再存在)。
我无法在主服务重新启动时清理僵尸 Bonjour
服务,因为最初注册的 mRegistrationListener
服务也不再存在。
我怀疑我采取了错误的方法:如何确保在主服务崩溃后我不会留下一堆僵尸 Bonjour
服务?
非特定于 Android Bonjour,您可以尝试按照此处答案中所述设置您的服务来处理崩溃:Can I call a method before my application go to crash
如果您无法将其设置为进行 unregisterService 调用,您应该能够将其设置为使用 ActivityManager 的 API killBackgroundProcesses。这需要将权限添加到您的清单:
android.permission.KILL_BACKGROUND_PROCESSES
如果我对你的理解正确的话,主要服务(带有服务器套接字的服务)registers/unregisters Nsd
服务,而后台服务 starts/stops 发现 Nsd
服务.我认为这就是你所做的,所以你的 "approach" 是正确的。
关于这个问题,欢迎大家AndroidNsd
。截至 Android
6.0 为止,框架中有很多 bugs 问题(您可以在其中找到您的问题)尚未得到修复,这使得开发人员改用其他框架。
回到问题上来,你可以尝试UncaughtExceptionHandler
,只要记住所有的回调都是由系统异步调用的,当它调用[=17时你可能会得到NPE
=],因为正如你所说,"it is no longer around".
关于服务清理,理论上是可以的,但是需要NsdManager
源代码定制后(需要更改一些方法的访问修饰符才能到达然后注销mRegistrationListener
来自另一个进程,这将导致从 NsdManager
的侦听器映射中删除它)。但是如果要在市场上发布该应用程序没有任何意义。
您可以 try/experiment 使用另一种解决方法。如果我没记错的话(可能有误),必要的清理是在禁用 Nsd
时进行的。我通过 adb
:
尝试过
// Disable
adb shell service call servicediscovery 2
// Enable
adb shell service call servicediscovery 2 i32 1
但是请注意,以编程方式进行这些调用可能并不简单,而且很可能需要 root,这再次限制了您的应用程序的受众。
关于@thril提出的killBackgroundProcesses()
方法,它以应用程序包名的字符串作为参数。但是 servicediscovery
不是应用程序,它是系统服务。此外,您可以尝试在运行时终止该进程(虽然我不知道是哪个进程),但要小心,您应该调查它对系统带来的影响,并确保该服务将在需要时再次启动(自动通过系统或手动)。同样,要执行此操作需要 root。
总结一下答案,在您继续 Nsd
之前,我强烈建议您对其 functionality/bugs 进行搜索,以免浪费您的时间和精力。除了上面提供的 link 之外的一些参考资料:
- NSD Device Lost Message Not Received on Disabling Wifi
P.S。就我个人而言,在与多个 Nsd
框架错误作斗争之后,最终编写了我自己的框架。
我的应用程序本质上是一个后台服务,需要偶尔注册一个 NSD
服务(Bonjour
服务),以便主程序能够发现套接字服务器 运行后台服务(应用又名 运行)。
如果我没看错 Android Bonjour Service doc,这就是启动 Bonjour
服务的方式(为简洁起见缩写):
mNsdManager = Context.getSystemService(Context.NSD_SERVICE);
mDiscoveryListener = new NsdManager.DiscoveryListener()
mNsdManager.discoverServices(
SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
...这就是你如何阻止它:
mNsdManager.unregisterService(mRegistrationListener);
这是我无法理解的部分:如果主要服务突然关闭,崩溃时注册的任何 Bonjour
服务都会保持 运行ning,即使它不再有目的(它帮助发现的套接字服务器不再存在)。
我无法在主服务重新启动时清理僵尸 Bonjour
服务,因为最初注册的 mRegistrationListener
服务也不再存在。
我怀疑我采取了错误的方法:如何确保在主服务崩溃后我不会留下一堆僵尸 Bonjour
服务?
非特定于 Android Bonjour,您可以尝试按照此处答案中所述设置您的服务来处理崩溃:Can I call a method before my application go to crash
如果您无法将其设置为进行 unregisterService 调用,您应该能够将其设置为使用 ActivityManager 的 API killBackgroundProcesses。这需要将权限添加到您的清单:
android.permission.KILL_BACKGROUND_PROCESSES
如果我对你的理解正确的话,主要服务(带有服务器套接字的服务)registers/unregisters Nsd
服务,而后台服务 starts/stops 发现 Nsd
服务.我认为这就是你所做的,所以你的 "approach" 是正确的。
关于这个问题,欢迎大家AndroidNsd
。截至 Android
6.0 为止,框架中有很多 bugs 问题(您可以在其中找到您的问题)尚未得到修复,这使得开发人员改用其他框架。
回到问题上来,你可以尝试UncaughtExceptionHandler
,只要记住所有的回调都是由系统异步调用的,当它调用[=17时你可能会得到NPE
=],因为正如你所说,"it is no longer around".
关于服务清理,理论上是可以的,但是需要NsdManager
源代码定制后(需要更改一些方法的访问修饰符才能到达然后注销mRegistrationListener
来自另一个进程,这将导致从 NsdManager
的侦听器映射中删除它)。但是如果要在市场上发布该应用程序没有任何意义。
您可以 try/experiment 使用另一种解决方法。如果我没记错的话(可能有误),必要的清理是在禁用 Nsd
时进行的。我通过 adb
:
// Disable
adb shell service call servicediscovery 2
// Enable
adb shell service call servicediscovery 2 i32 1
但是请注意,以编程方式进行这些调用可能并不简单,而且很可能需要 root,这再次限制了您的应用程序的受众。
关于@thril提出的killBackgroundProcesses()
方法,它以应用程序包名的字符串作为参数。但是 servicediscovery
不是应用程序,它是系统服务。此外,您可以尝试在运行时终止该进程(虽然我不知道是哪个进程),但要小心,您应该调查它对系统带来的影响,并确保该服务将在需要时再次启动(自动通过系统或手动)。同样,要执行此操作需要 root。
总结一下答案,在您继续 Nsd
之前,我强烈建议您对其 functionality/bugs 进行搜索,以免浪费您的时间和精力。除了上面提供的 link 之外的一些参考资料:
- NSD Device Lost Message Not Received on Disabling Wifi
P.S。就我个人而言,在与多个 Nsd
框架错误作斗争之后,最终编写了我自己的框架。