Android应用程序防止被LMK干掉

一、背景:项目中APP需要常驻后台,但Android的LMK(low memory kill)会根据自己的算法在内存不足时清理一些进程。如何尽量不让LMK干掉自己的成呢?

二、调查:
参考一:http://bbs.csdn.net/topics/360088771#r_72861243
引用


Android 系统对于内存管理有自己的一套方法,为了保障系统有序稳定的运信,系统内部会自动分配,控制程序的内存使用。当系统觉得当前的资源非常有限的时候,为了保 证一些优先级高的程序能运行,就会杀掉一些他认为不重要的程序或者服务来释放内存。这样就能保证真正对用户有用的程序仍然再运行。如果你的 Service 碰上了这种情况,多半会先被杀掉。但如果你增加 Service 的优先级就能让他多留一会,我们可以用 setForeground(true) 来设置 Service 的优先级。

为什么是 foreground ? 默认启动的 Service 是被标记为 background,当前运行的 Activity 一般被标记为 foreground,也就是说你给 Service 设置了 foreground 那么他就和正在运行的 Activity 类似优先级得到了一定的提高。当让这并不能保证你得 Service 永远不被杀掉,只是提高了他的优先级。

有一个方法可以给你更清晰的演示,进入 $SDK/tools 运行命令

代码:
# adb shell dumpsys activity|grep oom_adj  
 
Running Norm Proc # 6: oom_adj=  0 ProcessRecord{43635cf0 12689:com.roiding.netraffic/10028}  
Running Norm Proc # 5: oom_adj=  7 ProcessRecord{436feda0 12729:com.android.browser/10006}  
Running Norm Proc # 4: oom_adj=  8 ProcessRecord{4367e838 12761:android.process.acore/10016}  
Running Norm Proc # 3: oom_adj=  8 ProcessRecord{43691cd8 12754:com.google.process.gapps/10000}  
Running PERS Proc # 1: oom_adj=-12 ProcessRecord{43506750 5941:com.android.phone/1001}  
Running PERS Proc # 0: oom_adj=-100 ProcessRecord{4348fde0 5908:system/1000} 

返 回的一大堆东西,观察 oom_adj 的值,如果是大于 8 一般就是属于 backgroud 随时可能被干掉,数值越小证明优先级越高,被干掉的时间越晚。你看phone的程序是 -12 说明电话就是电话,其他什么都干了了,也的能接电话对吧。另外还有一个 -100 的,更邪乎因为是 system 如果他也完蛋了,你得系统也就挂了,嘿嘿。



参考二:http://www.cnblogs.com/perseus/archive/2012/01/11/2319660.html

引用

通过在androidmanifest.xml中的application标签中加入android:persistent="true" 属性后的确就能够达到保证该应用程序所在进程不会被LMK杀死。但有个前提就是应用程序必须是系统应用,也就是说应用程序不能采用通常的安装方式。必须将应用程序的apk包直接放到/system/app目录下。而且必须重启系统后才能生效。
除了一般的几种优先级外,还存在着coreserver,system这样的永远不会被LMK回收的优先级。系统中的电话应用就是coreserver优先级的。
通过查看源代码可以知道,只有应用程序的flag同时为FLAG_SYSTEM和FLAG_PERSISTENT时,才会被设置为coreserver优先级

    if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {

    app.persistent = true;

    app.maxAdj = CORE_SERVER_ADJ;

    }


FLAG_SYSTEM在应用程序apk放在/system/app下时会被设置。所以才会出现只设置android:persistent="true"仍然会被杀死的情况。
测试时发现,将应用程序放到/system/app后不重启系统,仍然会被识别为普通的进程。当系统重新启动时,会在一开始就启动该进程并把它优先级设置为coreserver。
通过dumpsys activity命令能够很明显的看出其中差别。
  Running processes (most recent first):
  App # 3: adj= 2/1 ProcessRecord{30858c20 1877:com.android.email/10014} (started-services)
  PERS # 2: adj=-100/0 ProcessRecord{308fb390 1713:system/1000} (fixed)
  App # 1: adj= 0/0 ProcessRecord{30908198 1794:android.process.acore/10005} (top-activity)
  PERS # 0: adj= -12/0 ProcessRecord{3090d488 1789:xiao.xiong.test/10026} (fixed)
而且adj=-12时,这个进程通过ddms手动stop后会立即启动


参考三:关于提高Android程序Service优先级的实践
http://gqdy365.iteye.com/admin/blogs/2148975

参考四:http://blog.sina.com.cn/s/blog_6f7ce0e60100viip.html

三、解决方案:
综上我们可以得到下面的结论:
1、给Application设置android:persistent="true"属性,要配合ApplicationInfo.FLAG_SYSTEM,所以说,只要预装的软件才可以;

2、APP中创建Service,并提搞Service的优先级,具体看我的文章:
关于提高Android程序Service优先级的实践
http://gqdy365.iteye.com/admin/blogs/2148975

3、在APP被kill掉之后怎么重启
方法一:在service的ondestroy中重启service;这种方法不可行,因为service被kill掉时根本不执行ondestroy方法;
方法二:onStartCommand(Intent,int,int)方法中更改flags为START_STICKY

引用

每次调用startService(Intent)的时候,都会调用该Service对象的onStartCommand(Intent,int,int)方法,这个方法return 一个int值,return 的值有四种:

START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。

START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务。

START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。

START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。

你可能感兴趣的:(android)