Android保证进程不被杀掉的方法

来源:互联网 发布:淘宝上卖的vr是真的吗 编辑:程序博客网 时间:2024/04/28 09:29

今天看到个知识点,如何后台保证service存活

**1**onStartCommand方法,返回START_STICKY

2提升service优先级AndroidManifest.xml文件中对于intent-filter可以通过android:priority = “1000”

3提升service进程优先级 Android中的进程是托管的,当系统进程空间紧张的时候,会依照优先级自动进行进程的回收。Android将进程分为6个等级,它们按优先级顺序由高到低依次是: 1.前台进程( FOREGROUND_APP) 2.可视进程(VISIBLE_APP ) 3. 次要服务进程(SECONDARY_SERVER ) 4.后台进程 (HIDDEN_APP) 5.内容供应节点(CONTENT_PROVIDER) 6.空进程(EMPTY_APP)

可是真的只有这么些吗 研究了一早上 发现一般有这么些方案

1:后台他是首先开启一个c进程,将需要保活的service名字传递进去
然后定时给自己主进程发一个intent,如果主进程挂掉了,就可以顺利拉起来保证存活。
所以他只是一个没有主动权的消息轮询器,说是守护其实很勉强
而且,这是要建立在保证c进程不挂的基础上,才能轮询,但是就目前来看,只有5.0以下的非国产机才会有这样的漏洞。也就是说在force close的时候,系统忽略c进程的存在,5.0以上包括5.0的哪怕源生系统也会连同c进程一起清理掉,国产机就更不用说了。就算是这样,在5.0以下的非国产机上,如果安装了获取root权限的360\cm的话,也是可以直接清理掉,也就是说会失效。
而且他不但不算守护,而且还是单向的,也就是说只能a保b,b保不了a;a保b也不是在b死了立刻拉起来,要等到了时间才会去拉。
最后,就算把刚才说的都排除掉,在很少的一部分手机,也就是低端且没有安装安全软件的手机上,他仍然无法保证时时存活。

2:
第一,如果a守护b,则b挂掉的一瞬间,a就应该把b启动起来
第二,a和b应该是互相守护,无论谁挂掉,对方就把他拉起来
那么怎么样才能实现双向守护呢?首先我们想到的是fork这个函数,他会创建一个子进程,然后在父进程中调用waitpid()这个函数,这是一个阻塞函数,他会一直wait到子进程挂掉,才会继续向下执行,利用这个机制,我们可以在主进程的c层fork一个子进程,然后父进程就可以监听到子进程的死亡,死亡的时候再重启子进程。
似乎可以用这个机制改进刚刚上面分析的那个工程,因为这样的话:1,无法直接杀掉子进程。2、子进程不死,他就会按时发intent给父进程。
这样做,普通杀是没有问题。但是force close不会按照你的要求先杀孩子,等你把孩子启动起来,再杀父亲,然后坐视子进程在那不管,三方软件自不必说。那么先杀父进程的话,子进程就没办法监听到父进程的死亡吗?
有朋友要说可以利用linux的进程领养机制,如果父进程挂掉,那么子进程就会被linux的init进程领养,进程所对应的父进程id也会变成1。这的确是一个很好的标示,但是要怎样监听这个状态的变化呢?轮询获取父进程id,然后判断是否等于1?那么轮询的间隔为多少合适?1秒间隔算短算长?设为1秒的话force close掉你的时候,根本不会等到你那每秒正时正点的轮询点上,会被forceclose直接干掉,我试过更短的时间,基本要小到小于10毫秒的时间间隔,才有可能再force close的时候检测到,并成功拉起父进程。注意我的关键词,小于10毫秒!才可能!对,一秒100次的检查,才有可能,只是可能!手机待机十分钟就已经可以开始烫手,三个小时电池发出了低电量警告。

3:使用管道
waitpid是阻塞函数,所以他一定是没有耗电问题的,即时性也没有问题。那么问题就集中在了子进程如何监听到父进程的死亡上面,把那个轮询替掉。
然后,我想到的是管道,linux中有多种ipc通信机制,管道是最基本的一种通信方式,且这种管道只能在父子进程间建立,于是我想是否能利用这个机制呢?在父子进程间建立管道,但是并不写入数据,只是使用阻塞方法在另一端去读取管道,这样如果对方进程挂掉,管道会被破坏,那么另一端的读取方法就会执行返回,由此确定对方挂掉然后重启对方。
但是问题又来了
1、用ps命令发现fork出来的进程内存占用很大
2、fork出来的进程名字与父进程名字相同
原因:
1、fork函数调用的时候,会复制父进程的全部内存,因为父进程一定是我们需要保证常驻的Java进程,他在初始化的时候是fork的一个zygote进程,即时在应用刚初始化的时候fork,进程里面是有一个java虚拟机的内存在里面的,最少一二十兆是有了。fork出来子进程多的内存最后都会算到我们自己应用的内存中。
2、机制如此

——————————————————————-
3最终解决方案
我们继续讨论内存的问题,如何不用fork也能建立管道呢。于是我想到了运行一个二进制可执行文件,这样他是一个相对独立的进程,但是又可以建立父子进程之间的管道。将真正用来实现的子进程写到一个二进制文件中(对应文件源码/MarsDaemon/LibMarsdaemon/jni/daemon.c),这样既解决了内存问题,又可以自己给新的进程命名。
问题解决了吗?没有,直接execute一个binary文件之后
1、发现代码不再继续向下执行
2、waitpid又不能用了
原因和解决方法:
1、直接运行一个二进制文件,他会占用原进程,于是我们这里仅将fork用作一个启动binary的工具,fork终于回归到了Linus希望他作用的地方
2、父子进程间的管道是单向的,于是我们可以建两根管道。ab两个进程,建12两个管道。a进程关掉管道1的写端,堵瑟调用管道2的读取方法;b进程关掉管道2的写端,堵瑟调用管道1的读取方法。这样就可以实现双向监听。任何一方监听到对方死掉就作出相应的动作,启动对方。至此,完全摒弃开始的fork方案。
然后说一下监听到对方进程死后的策略

你会说谁监听到对方死了,就直接拉起来就好了呀。

问题:

1、重新拉起来要重新建立双管道,子进程挂掉,父进程把他重启起来建立双管道还好说,如果父进程挂掉,子进程把父进程启动起来,他们之间就无法建立连接,而且如果中间出了差错,同步起来很费劲,于是我选择,无论谁监听到谁死了,都重启对方,然后自杀,重新初始化!

2、如果执行force close, 系统先杀父进程,子进程监听到之后拉起父进程然后自杀,但是系统杀你两个进程的间隔时间非常非常短,父进程刚起来还没来得及初始化,系统赶过来杀父进程。有的手机强杀之后很短一段时间无法拉起父进程。于是我选择用第三个进程。

第三个进程和之前的父子进程都没有任何关系,他的作用只是用做拉起常驻进程。父子进程无论谁监听到谁死,都拉起第三个进程,第三个进程负责拉起常驻进程,然后自杀。(用户实际上是看不到他的存在的,因为他可能只存活不到一秒就自杀了)
此方式适用于android5.0一下,5.0以上会直接杀掉这个进程组中的进程,所以这个进程也会被杀掉

那么5.0以上怎么办呢

进程a给文件1加锁,然后阻塞读取文件2的锁,进程b给文件2加锁,然后阻塞读取文件1的锁,如果对方进程挂掉,他所在进程所持有的文件锁会立即释放,那么另一个进程就可以读取到被释放文件锁的文件,监听到对方挂掉。

实现这个方案,首先使用的java代码,java里是有一套文件锁的api的,但是写完之后编译时报错。我就不写demo截图了,错误的信息是死锁exception,两个进程不能互相持有对方的锁。java的编译器可真多事儿,于是我想能不能用三个进程,1拿2的锁,2拿3的锁,3拿1的锁,还是不行,deadlock exception.

怀着忐忑的心情我用c来实现尝试,庆幸的是c中没有问题。原理通了,剩下的就是把代码写健壮,最难搞的问题就是同步问题,ab两个进程,如果b进程还没给文件加锁,a就开始读锁,那么就会误以为b进程挂掉了。需求:
1、需要让a进程先把文件1锁了,然后不去读文件2,等b进程做同样的操作之后,两边再同时读取对方的锁。
2、需要考虑第程序重新进入的初始化状态与单个进程等待的状态冲突问题
3、不能耗时!!时间很重要,后面会说到

这一块确实想了一晚上才想出来合适的解决方案,首先肯定不能用管道、信号这些进程间通信,连memset都不要考虑,因为耗时,java层的机制就更不用考虑了!那么就只能用一些标示位手段,比如一个文件在了就代表一个进程在了,一个文件没了,就代表一个进程锁好了。
于是最后的同步方案是:

1、4个文件,a进程文件a1,a2,b进程b1,b2

2、a进程加锁文件a1,b进程同理

3、a进程创建a2文件,然后轮询查看b2文件是否存在(这里可以轮询,因为时间很短),不存在代表b进程还没创建,b进程同理

4、a进程轮询到b2文件存在了,代表b进程已经创建并可能在对b1文件加锁,此时删除文件b2,代表a进程已经加锁完毕,允许b进程读取a进程的锁,b进程同理

5、a进程监听文件a2,如果a2被删除,代表b进程进行到了步骤4已经对b1加锁完成,可以开始读取b1文件的锁(不能直接监听a2文件删除,也就是不能跳过34步,这也是最难想的一部分,如果那样可能此时b进程还没创建,和b进程创建完成并加锁完成的状态是一样的,就会让进程a误以为进程b加锁完成),b进程同理

具体大概思想就是这样
详细的保活方案请看这个黑科技

https://github.com/Marswin/MarsDaemon

还有这个
http://blog.csdn.net/marswin89/article/details/50917098
我只是大概总结下 原文说得太多

0 0
原创粉丝点击