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,通过自测和测试复测,问题没有再出现。

相关推荐
吾日三省吾码1 小时前
JVM 性能调优
java
stm 学习ing1 小时前
FPGA 第十讲 避免latch的产生
c语言·开发语言·单片机·嵌入式硬件·fpga开发·fpga
湫ccc2 小时前
《Python基础》之字符串格式化输出
开发语言·python
弗拉唐2 小时前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
oi772 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
mqiqe2 小时前
Python MySQL通过Binlog 获取变更记录 恢复数据
开发语言·python·mysql
AttackingLin2 小时前
2024强网杯--babyheap house of apple2解法
linux·开发语言·python
少说多做3433 小时前
Android 不同情况下使用 runOnUiThread
android·java