安卓守护程序爬坑经历

4 篇文章 0 订阅
2 篇文章 0 订阅

       最近开发一个android电视上运行的软件,由于需要长时间运行,所以需要保证稳定性,以及在意外情况下能自动重启运行。要直接让应用程序本身保证无bug还是有一定难度,一般情况是外加守护程序(daemon)或者叫做看门口。以往的应用在pc端的应用中就是这么使用的,能达到需要的长期运行的效果。同样的方法也就确定在android上这么使用了。确定方案开始干。

       刚开始想着平移windows的守护程序,但是问题就随之而来。windows上可以直接OpenProcess 、共享内存交互、获取进程内存情况等各种信息;到android,这些都无对应功能函数。所以首先看看其他应用中都是使用什么方式实现守护程序功能。首先查到的是java的方式。

       android各种 前台后台进程介绍这里就不多说了。

1、使用java android的 Service 方式

       结果,模拟器可以用,手机可以用,android电视上无法拉起程序。查找各种权限原因等,都无法解决。更有病的是电视无法adb调试,使用的是海信的最近1-2年的型号。无法调试这大大增加了解决问题的难度。和售后沟通之后,答复是他们的电视都取消了这个功能,所以各个开发朋友以后得注意了要做产品,海信的首先必须不能采购。以后做电视二次开发类似的产品,都必须提前售后咨询好,要不是后患无穷。

       各种尝试几天后,java这个方式只能放弃。

2、linux原生接口。

       再次搜索之后得到有另一个途径,使用linux的fork方式。android本身仍然是linux系统,但是很多被阉割或者限制了,不过从搜索的结果看还是能实现的。反正也没有其他好办法,只能这么尝试。

       如果使用daemon方式就是两个程序,应该可以调用起来。但是作为普通apk程序,运行级别低,容易被系统kill。所以daemon就得运行级别高,最好是linux的bin程序。做bin程序也有很大麻烦:首先是安装包里面如何添加bin程序打包;其次是bin程序所在目录要能被访问。所以这个完整方式只能靠后了,而简单测试后使用直接apk自身fork的方式实现。(应用程序本身是ndk+qt开发)。

       大致daemon函数如下:

 

int CreateDaemon()

{

 

    struct sigaction sa;

    sa.sa_handler = SIG_IGN;

    sigemptyset(&sa.sa_mask);

    sa.sa_flags = 0;

    if(sigaction(SIGCHLD, &sa, NULL) < 0)

    {

        return -1;

    }

 

    int pid;

 

    if(pid=fork())

    {

       // return 0;

        exit(0);//是父进程,结束父进程

    }

    else if(pid< 0)

        exit(1);//fork失败。退出

    //是第一子进程,后台继续执行

/*    setsid();//第一子进程成为新的会话组长和进程组长

 

    //struct sigaction sa;

    sa.sa_handler = SIG_IGN;

    sigemptyset(&sa.sa_mask);

    sa.sa_flags = 0;

    if(sigaction(SIGCHLD, &sa, NULL) < 0)

    {

        return -1;

    }

 

    //并与控制终端分离

    if(pid=fork())

        exit(0);//是第一子进程,结束第一子进程

    else if(pid< 0)

        exit(1);//fork失败,退出

    */

    int i=0;

    qint64 nPid = nHostPid;

    while ( i++<10 )

    {

        usleep(5*1000*1000);

        //continue;

        //

        //if (nPid > 0)

        {

            QString strKill;

            //am stop org.qtproject.TestDaemon

           // strKill = strKill.sprintf("kill -9  %d", (int)nPid);

//             strKill = strKill.sprintf("am force-stop org.qtproject.TestDaemon");

 //           QProcess::execute(strKill);

            //am   force-stop org.qtproject.example.testMediaSdk

 

            strKill = strKill.sprintf("am force-stop org.qtproject.example.testMediaSdk");

           QProcess::execute(strKill);

        }

        usleep(5*1000*1000);

        //

        QString strProgram = "am";

        QString strCmp;

        strCmp = "start --user 0 -n org.qtproject.example.testMediaSdk/org.qtproject.qt5.android.bindings.QtActivity";

        QStringList arrArgs;

        arrArgs += "start";

        arrArgs += "--user";

        arrArgs += "0";

        arrArgs += "-n";

        //arrArgs += "org.qtproject.example.testMediaSdk/org.qtproject.qt5.android.bindings.QtActivity";

        arrArgs += "org.qtproject.TestDaemon/org.qtproject.qt5.android.bindings.QtActivity";

 

//        if ( QProcess::startDetached(strProgram, arrArgs, QString(), &nPid) )

//        {

//            qDebug("%s: start process ok\n");

//        }

//        else

//        {

//            qDebug("%s: start process false\n");

//        }

 

 

        QStringList arrArgs1;

        arrArgs1 += "start";

        arrArgs1 += "--user";

        arrArgs1 += "0";

        arrArgs1 += "-n";

        arrArgs1 += "org.qtproject.example.testMediaSdk/org.qtproject.qt5.android.bindings.QtActivity";

       // arrArgs += "org.qtproject.TestDaemon/org.qtproject.qt5.android.bindings.QtActivity";

 

        if ( QProcess::startDetached(strProgram, arrArgs1, QString(), &nPid) )

        {

            qDebug("%s: start process ok\n");

        }

        else

        {

            qDebug("%s: start process false\n");

        }

        //

    }

    exit(0);

 

    return 0;

}

 

这里面主要为测试代码,这个是循环启动10次

 

其中测试 kill 命令的 是没成功的。

有几个问题:

1、fork需要两次,这样摆脱原始进程的影响,实际测试过程中不同的手机或者电视,有的如果只是fork一次,daemon确实会因为原始进程退出而退出。

2、这里使用的是qt的进程启动命令,其实就是封装了2次fork过程。这里如果不使用detach方式启动程序,也会有关联被杀死的问题。

3、文件锁,这里没有加入。在实际应用中添加了,这个是用于判断主程序是否退出的通信方式。这个也遇到了不少坑

       1)电视上 android很多目录无法访问,这样就无法创建文件锁。需要找到一个可读写文件的目录。

       2)如果不用文件锁,使用mutex+mmap方式(共享内存中的锁)。也不行,因为要跨进程,mmap也得使用命名文件。

       3)共享内存,android禁用了linux的共享内存

       4)命名的semaphore, 进程异常退出无法正确计数;另外,android也不支持命名semaphore。

 

   经过这些折腾,守护程序能在电视上正确的拉起程序。另外是程序如果异常退出,电视会弹框,手机上并不会。这个弹框要等5-10分钟才会自动消失,不用理会。

       (android7/8 以上的版本测试)程序主要功能为连接主服务,播放视频、图片、文字等信息。属于信息展示系统/信息发布系统。进一步需要将daemon独立开。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值