• amlogic 机顶盒关闭DLNA 后,手机还能搜到盒子


            S905L3 带有投屏的功能,并通过 com.droidlogic.mediacenter.dlna.MediaCenterService 服务的启动和停止来开启和关闭DLNA功能,但是在测试中发现机顶盒关闭DLNA后,手机还能搜索到盒子。我在复测中发现关闭后有时很难很久搜索到盒子,有时却很容易搜索到。

            通过查看日志,发现打开和关闭盒子,com.droidlogic.mediacenter进程分别只有一条日志,线索有限。

    行  266: 05-31 09:35:54.089  4603  4603 D WeakRefService: net.droidlogic.action.dlna   state:true
    行 1171: 05-31 09:36:04.272  4603  4603 D WeakRefService: net.droidlogic.action.dlna   state:false

            调试了盒子设置界面打开和关闭DLNA的流程,大概已经熟悉,但是没有找出关闭的流程有什么问题,设置APP的逻辑比较简单,接口jar包dlna.jar则代码较多,不太容易完全掌握其逻辑。难于定位是设置APP调用有问题还是调用的接口本身有问题。但是我想,虽然不知道关闭DLNA需要调用什么代码和接口,而且关闭会失败,很难定位关闭的正确流程。但是可以通过定位开机打开DLNA调用了什么接口,从而能猜测到关闭DLNA需要什么接口。

            于是开机后打开DLNA, 一路的设置断点,且每个断点都在手机上确认能否搜到盒子,最后在adv.start()执行后,手机就能搜到盒子了。

    1. public boolean start() {
    2. Debug.d("DEVICE", "========httpServerList.start");
    3. int retryCnt = 0;
    4. int bindPort = this.getHTTPPort();
    5. HTTPServerList httpServerList;
    6. for(httpServerList = this.getHTTPServerList(); !httpServerList.open(bindPort); bindPort = this.getHTTPPort()) {
    7. ++retryCnt;
    8. if (100 < retryCnt) {
    9. return false;
    10. }
    11. this.setHTTPPort(bindPort + 1);
    12. }
    13. httpServerList.addRequestListener(this);
    14. httpServerList.start();
    15. Advertiser adv = new Advertiser(this);
    16. this.setAdvertiser(adv);
    17. adv.start();
    18. Debug.d("DEVICE", "========SSDPSearchSocketList.start");
    19. if (HostInterface.getAvailNet() != null && HostInterface.getAvailNet().length > 0) {
    20. this.setSSDPBindAddress(HostInterface.getAvailNet());
    21. }
    22. SSDPSearchSocketList ssdpSearchSockList = this.getSSDPSearchSocketList();
    23. if (!ssdpSearchSockList.open()) {
    24. return false;
    25. } else {
    26. ssdpSearchSockList.addSearchListener(this);
    27. ssdpSearchSockList.start();
    28. this.peers.clear();
    29. return true;
    30. }
    31. }

           Advertiser继承线程类,start后整个线程就跑起来了。他的逻辑还是很清楚,先调用byebye,如果线程关联的设备跟其他设备绑定了,先解绑(花5秒钟),然后对外广播,设备激活了,之后每隔320秒广播一次。在这个类里面也能容易发现关闭DLNA要调用stopAdvertiser,再设置断点,发现调用stopAdvertiser后,这个线程停止不下来,于是还是会320秒广播一次。

    1. public class Advertiser extends Thread
    2. {
    3. private static Thread advertise;
    4. private Device device;
    5. public Advertiser(final Device dev) {
    6. this.setDevice(dev);
    7. }
    8. public void setDevice(final Device dev) {
    9. this.device = dev;
    10. }
    11. public Device getDevice() {
    12. return this.device;
    13. }
    14. public void stopAdvertiser() {
    15. if (Advertiser.advertise != null) {
    16. final Thread tmpThread = Advertiser.advertise;
    17. tmpThread.interrupt();
    18. Advertiser.advertise = null;
    19. }
    20. }
    21. @Override
    22. public void run() {
    23. Advertiser.advertise = Thread.currentThread();
    24. this.getDevice().byebye();
    25. try {
    26. Thread.sleep(5000L);
    27. }
    28. catch (InterruptedException e) {
    29. e.printStackTrace();
    30. while (true) {
    31. this.getDevice().announce();
    32. try {
    33. Thread.sleep(320000L);
    34. }
    35. catch (InterruptedException ex) {break;}
    36. }
    37. }
    38. finally {
    39. while (true) {
    40. this.getDevice().announce();
    41. try {
    42. Thread.sleep(320000L);
    43. }
    44. catch (InterruptedException ex2) {}
    45. }
    46. }
    47. }
    48. static {
    49. Advertiser.advertise = null;
    50. }
    51. }

          在这里就可以发现问题的所在,当调用stopAdvertiser出发线程中断时,run 循环对InterruptedException 异常没有做任何处理,所以也不会停止,可以考虑捕获异常时,跳出循环。但是dlna.jar没有源码,只有jar包,因此要做反编译处理。

          找到S905L3的编译环境,查看是用的jdk 8,  把该jdk加入到环境变量 PATH。

          生成class文件,把dlna.jar拖入eclipse 或者 android studio, 找到相应的类,可以直接看到代码,然后把代码复制到一个空的Advertiser.java文件上,修改对应的逻辑。然后用命令: javac Advertiser.java, 生成新的Advertiser.class

          第一次修改只在抛异常处增加break语句,但是编译后发现break语句会被优化掉,第二次修改把捕获中断异常放到循环外,问题得到解决。

    1. //修改前
    2. try {
    3. Thread.sleep(5000L);
    4. }
    5. catch (InterruptedException e) {
    6. e.printStackTrace();
    7. while (true) {
    8. this.getDevice().announce();
    9. try {
    10. Thread.sleep(320000L);
    11. }
    12. catch (InterruptedException ex) {}
    13. }
    14. }
    15. //第一次修改
    16. try {
    17. Thread.sleep(5000L);
    18. }
    19. catch (InterruptedException e) {
    20. e.printStackTrace();
    21. while (true) {
    22. this.getDevice().announce();
    23. try {
    24. Thread.sleep(320000L);
    25. }
    26. catch (InterruptedException ex) { break;}
    27. }
    28. }
    29. //第二次修改
    30. try {
    31. Thread.sleep(5000L);
    32. while (true) {
    33. this.getDevice().announce();
    34. Thread.sleep(320000L);
    35. }
    36. }
    37. catch (InterruptedException e) {
    38. e.printStackTrace();
    39. }

          解包:unzip dlna.jar

          打包:把新的Advertiser.class替换到解包出来的文件夹, 用下命令打包:jar -uvf dlna.jar org/cybergarage/upnp/device/Advertiser.class。dlna.jar就由旧的dlna.jar变成了新的dlna.jar。

          用新的dlna.jar编译设置APK,通过自测和测试复测,问题没有再出现。

         

  • 相关阅读:
    JVM第七讲:JVM 基础 - Java 内存模型详解
    GPT语言模型
    事务死锁排查
    python 最快多长时间学完?
    vue3 解决双击与单击事件的冲突
    Dubbo传输层及交换层实现
    「分辨率比拼」还不够,4D成像雷达进入“软”竞争时代
    0基础学习VR全景平台篇 第107篇:全景图调色和细节处理(上,地拍)
    深入掌握 Makefile 与 Make 工具:高效管理自动化编译的核心原理和最佳实践
    java毕业设计车辆监管系统mybatis+源码+调试部署+系统+数据库+lw
  • 原文地址:https://blog.csdn.net/yangzex/article/details/130988338