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()执行后,手机就能搜到盒子了。

java 复制代码
    public boolean start() {
        Debug.d("DEVICE", "========httpServerList.start");
        int retryCnt = 0;
        int bindPort = this.getHTTPPort();

        HTTPServerList httpServerList;
        for(httpServerList = this.getHTTPServerList(); !httpServerList.open(bindPort); bindPort = this.getHTTPPort()) {
            ++retryCnt;
            if (100 < retryCnt) {
                return false;
            }

            this.setHTTPPort(bindPort + 1);
        }

        httpServerList.addRequestListener(this);
        httpServerList.start();
        Advertiser adv = new Advertiser(this);
        this.setAdvertiser(adv);
        adv.start();
        Debug.d("DEVICE", "========SSDPSearchSocketList.start");
        if (HostInterface.getAvailNet() != null && HostInterface.getAvailNet().length > 0) {
            this.setSSDPBindAddress(HostInterface.getAvailNet());
        }

        SSDPSearchSocketList ssdpSearchSockList = this.getSSDPSearchSocketList();
        if (!ssdpSearchSockList.open()) {
            return false;
        } else {
            ssdpSearchSockList.addSearchListener(this);
            ssdpSearchSockList.start();
            this.peers.clear();
            return true;
        }
    }

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

java 复制代码
public class Advertiser extends Thread
{
    private static Thread advertise;
    private Device device;
    
    public Advertiser(final Device dev) {
        this.setDevice(dev);
    }
    
    public void setDevice(final Device dev) {
        this.device = dev;
    }
    
    public Device getDevice() {
        return this.device;
    }
    
    public void stopAdvertiser() {
        if (Advertiser.advertise != null) {
            final Thread tmpThread = Advertiser.advertise;
            tmpThread.interrupt();
            Advertiser.advertise = null;
        }
    }
    
    @Override
    public void run() {
        Advertiser.advertise = Thread.currentThread();
        this.getDevice().byebye();
        try {
            Thread.sleep(5000L);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
            while (true) {
                this.getDevice().announce();
                try {
                    Thread.sleep(320000L);
                }
                catch (InterruptedException ex) {break;}
            }
        }
        finally {
            while (true) {
                this.getDevice().announce();
                try {
                    Thread.sleep(320000L);
                }
                catch (InterruptedException ex2) {}
            }
        }
    }
    
    static {
        Advertiser.advertise = null;
    }
}

在这里就可以发现问题的所在,当调用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语句会被优化掉,第二次修改把捕获中断异常放到循环外,问题得到解决。

java 复制代码
        //修改前
        try {
            Thread.sleep(5000L);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
            while (true) {
                this.getDevice().announce();
                try {
                    Thread.sleep(320000L);
                }
                catch (InterruptedException ex) {}
            }
        }

        //第一次修改
        try {
            Thread.sleep(5000L);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
            while (true) {
                this.getDevice().announce();
                try {
                    Thread.sleep(320000L);
                }
                catch (InterruptedException ex) { break;}
            }
        }

        //第二次修改
        try {
            Thread.sleep(5000L);
            while (true) {
                this.getDevice().announce();
                Thread.sleep(320000L);
            }
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }

解包:unzip dlna.jar

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

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

相关推荐
冻柠檬飞冰走茶5 小时前
字母移动游戏题解:贪心求最长可保留连续子串(附 C 实现)
c语言·开发语言·数据结构·算法·动态规划
文丑颜不良啊5 小时前
LeetCode2161~2180题目解析
java·leetcode
FRing035 小时前
vue2干货总结7(自定义指令、插槽、单页应用程序、路由的使用(VueRouter))
开发语言·前端·vue.js·vue2
雪落漂泊5 小时前
C++算法 二分查找篇(上)
开发语言·c++·算法
波力海苔夹心脆6756 小时前
C# WPF 资源字典详解:ResourceDictionary、MergedDictionaries 与自定义控件案例
开发语言·c#·wpf·入门教程·resource·资源字典
不会算法的笨小孩6 小时前
异常的使用以及会出现的问题
开发语言·c++·c++11·异常
文丑颜不良啊7 小时前
LeetCode2141~2160题目解析
java·leetcode
LabVIEW开发7 小时前
LabVIEW 连接板:28 个端子怎么排,优先级怎么定
java·算法·labview
天天被压力7 小时前
【A股分钟级高频数据完全手册 #07】北交所历史分钟K线接口:京市Pro版分时批量
java·人工智能·python
天天被压力7 小时前
【A股分钟级高频数据完全手册 #08】股票日、分时数据接口对比:普通分时与Pro版差异实测
java·人工智能·python