【问题标题】:Android : Stopping a Bonjour service left running after the parent process quit abrubtlyAndroid:在父进程突然退出后停止 Bonjour 服务继续运行
【发布时间】:2016-12-07 22:51:04
【问题描述】:

我的应用本质上是一个后台服务,它需要偶尔注册一个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 服务都会继续运行,即使它不再有目的(套接字它帮助发现的服务器不再存在)。

当主服务重新启动时,我无法清理僵尸Bonjour 服务,因为该服务最初注册的mRegistrationListener 也不再存在。

我怀疑我采取了错误的方法:我如何确保在主服务崩溃后不会留下一堆僵尸Bonjour 服务?

【问题讨论】:

    标签: android android-service android-networking android-nsd


    【解决方案1】:

    非特定于 Android Bonjour,您可以尝试通过设置您的服务来处理崩溃,如下面的答案所述:Can I call a method before my application go to crash

    如果您无法将其设置为进行 unregisterService 调用,您应该可以将其设置为使用 ActivityManager 的 API killBackgroundProcesses。这需要向您的清单添加权限:

    android.permission.KILL_BACKGROUND_PROCESSES
    

    【讨论】:

    • 谢谢,用UncaughtExceptionHandler 捕获未捕获的异常可能是可行的方法——尽管我希望有一种方法可以在主进程中运行 Bonjour 服务(我发现 Android 实现没有允许该选项)。如果接下来几天没有更好的结果,我会接受你的回答。
    • 我同意,您会认为有适当的方法来处理它。我找不到任何支持该理论的文档,但它可能会由操作系统处理。可能是谷歌认为人们可能根本不想这样做,所以他们应该自动处理它!
    • 感谢@thril,使用UncaughtExceptionHandler 取消注册服务为我工作(我通过在服务注册后几秒钟使服务崩溃,使用在单独线程中运行的守护程序计时器成功测试)
    【解决方案2】:

    如果我理解正确,主要服务(带有服务器套接字的服务)注册/取消注册Nsd 服务,而后台服务启动/停止发现Nsd 服务。我认为这就是你所做的,所以你的“方法”是正确的。

    关于这个问题,我应该欢迎你到AndroidNsd。从 Android 6.0 开始,有很多 bugs 的框架(您可以在其中找到您的问题)尚未修复,这使得开发人员可以改用其他框架。

    回到这个问题,你可以试试UncaughtExceptionHandler,只要记住所有的回调都是系统异步调用的,当它调用mRegistrationListener.onServiceUnregistered()时你可能会得到NPE,因为正如你所说, “它已经不在了”.

    关于服务清理,理论上是可以的,但是只有在NsdManager源代码自定义之后(需要更改一些方法的访问修饰符才能到达然后从另一个进程注销mRegistrationListener,这会导致从NsdManager 的监听器映射中删除它)。但是,如果要在市场上发布应用程序,则没有任何意义。

    您可以尝试/试验另一种解决方法。如果我没记错(可能记错了),在禁用Nsd 时会进行必要的清理。我通过adb尝试过:

    // Disable
    adb shell service call servicediscovery 2
    // Enable
    adb shell service call servicediscovery 2 i32 1
    

    但请注意,以编程方式进行这些调用可能并非易事,而且很可能需要 root,这再次限制了您的应用的受众。

    关于@thril 提出的killBackgroundProcesses() 方法,它接受一个带有应用程序包名的字符串作为参数。但是servicediscovery 不是应用程序,而是系统服务。另外,您可以尝试在运行时杀死该进程(虽然我不知道是哪个),但是要小心,您应该调查它给系统带来的影响,并确保在需要时再次启动该服务(自动通过系统或手动)。同样,要做到这一点,需要根。

    总结答案,在您继续使用Nsd 之前,我强烈建议您对其功能/错误进行搜索,以避免可能浪费您的时间和精力。除了上面提供的链接之外的一些参考资料:

    1. NSD Device Lost Message Not Received on Disabling Wifi
    2. NsdManager doesn't stop service discovery

    附:就我个人而言,在解决了多个 Nsd 框架错误之后,我最终编写了自己的框架。

    【讨论】:

    • 谢谢@Onik,最终使用UncaughtExceptionHandler 按设计工作,我通过使用守护程序计时器(Timer timer = new Timer(true) ; timer.schedule(new SimulateUncaughtException(), 2000);)从单独的线程崩溃主服务成功测试
    • 很好@Hugo,在单独的线程中处理Nsd 工作是个好主意,-显然在这种情况下你有时间取消注册服务。虽然,我仍然建议检查所有 Nsd 回调,尤其是在打开/关闭 Wifi (Ethernet) 时...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-01
    • 2013-04-16
    • 2021-11-25
    • 1970-01-01
    • 2020-03-02
    相关资源
    最近更新 更多