Android进程守护详解及解决方案
1.进程守护
Android应用在运行过程中有一些服务进程,该些进程通常执行一些后台服务,这就要求这些进程要常驻在应用中。但目前市面上的一些安全防护应用会杀死应用的进程,
为保证我们的应用的服务进程持久的存活,就引出了进程守护的定义。
2.解决方案
1.提高优先级
这个办法对普通应用而言,应该只是降低了应用被杀死的概率,但是如果真的被系统回收了,还是无法让应用自动重新启动!
2.让service.onStartCommand返回START_STICKY
通过实验发现,如果在adb shell当中kill掉进程模拟应用被意外杀死的情况(或者用360手机卫士进行清理操作),如果服务的onStartCommand返回START_STICKY,
在eclipse的进程管理器中会发现过一小会后被杀死的进程的确又会出现在任务管理器中,貌似这是一个可行的办法。
但是如果在系统设置的App管理中选择强行关闭应用,这时候会发现即使onStartCommand返回了START_STICKY,应用还是没能重新启动起来!
3.android:persistent="true"
网上还提出了设置这个属性的办法,通过实验发现即使设置了这个属性,应用程序被kill之后还是不能重新启动起来的!
4.让应用成为系统应用
实验发现即使成为系统应用,被杀死之后也不能自动重新启动。但是如果对一个系统应用设置了persistent="true",情况就不一样了。
实验表明对一个设置了persistent属性的系统应用,即使kill掉会立刻重启。
一个设置了persistent="true"的系统应用,在android中具有core service优先级,这种优先级的应用对系统的low memory killer是免疫的!
而普通应用要想成为系统应用就必须要用目标机器的签名文件进行签名,但这样又造成了应用无法保证兼容所有不同厂商的产品。
5.Intent.ACTIONTIMETICK
注册系统广播Intent.ACTION_TIME_TICK,这个广播每分钟发送一次,我们可以每分钟检查一次Service的运行状态,如果已经被结束了,就重新启动Service。
它的优点就是间隔时间短而且非常稳定, 而其他的广播并不能保证这一点,当然,在具体的应用中还是要根据需求使用, 结合其他广播来保证自己的service一定会被重启.
1、Intent.ACTION_TIME_TICK的使用
我们知道广播的注册有静态注册和动态注册,但此系统广播只能通过动态注册的方式使用。即不能通过在manifest.xml里注册的方式接收到这个广播,只能在代码里通过
registerReceiver()方法注册。
IntentFilter filter = newIntentFilter(Intent.ACTION_TIME_TICK);
MyBroadcastReceiver receiver = new MyBroadcastReceiver();
registerReceiver(receiver, filter);
2、广播接收器MyBroadcastReceiver extends BroadcastReceiver的onReceive里
boolean isServiceRunning = false;
if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) {
ActivityManager manager = (ActivityManager)AppApplication.getContext().getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service :manager.getRunningServices(Integer.MAX_VALUE)) {
if("so.xxxx.xxxxService".equals(service.service.getClassName())){
isServiceRunning = true;
}
}
if (!isServiceRunning) {
Intent i = new Intent(context, xxxService.class);
context.startService(i);
}
}
6. 使用JNI
使用Jni,在 c端 fork进程,检测Service是否存活,若Service已被杀死,则进行重启Service.
至于检测方式,可以轮询获取子进程Pid,若为1, 则说明子进程被Init进程所领养,已经成为了孤儿进程.
但是这种方式比较消耗电量,并且由于不同手机系统定制的改变,当应用被强制停止时,父进程并不一定被真正杀死,因此在一些特定机型上是无法通过此方式进行判断.
这里推荐使用liunx socket的方式进行类似心跳包的检测,并且当触发检测Service是否被杀死之前,需要判断应用是否已经被卸载,
如果应用已经被卸载,则不再进行检测Service行为,直接调用exit(0)退出子进程,避免浪费系统资源和消耗电量.
注意: 目前在Android 5.0系统上会把fork出来的进程放到一个进程组里, 当程序主进程挂掉后,也会把整个进程组杀掉, 因此用fork的方式也无法在Android5.0及以上系统实现守护进程. 这个是系统层面的限制,当然也是为了优化整个的系统环境,守护进程给手机带来的体验并不好。
7.双进程守护