Android进程保活主要包括以下两个方面:
(1)Android进程优先级提高
(2)Android进程被杀之后拉起复活
Low Memory Killer
Android系统会依据系统资源和进程优先级(oom_adj)对进程进行回收,这即是Low Memory Killer规则。
进程的优先级
进程的优先级(oom_adj),划分5级:
- 前台进程(Foreground process)
- 可见进程(Visible process)
- 服务进程(Service process)
- 后台进程(Background process)
- 空进程(Empty process)
adj级别 | adj取值 | adj解释 |
---|---|---|
UNKNOWN_ADJ | 16 | 一般指将要会缓存进程,无法获取确定值 |
CACHED_APP_MAX_ADJ | 15 | 不可见进程adj最大值 |
CACHED_APP_MIN_ADJ | 9 | 不可见进程adj最小值 |
SERVICE_B_AD | 8 | B list中的service使用可能性较小 |
PREVIOUS_APP_ADJ | 7 | 上一个App的进程(往往通过按返回键) |
HOME_APP_ADJ | 6 | Home的进程 |
SERVICE_ADJ | 5 | 服务进程 |
HEAVY_WEIGHT_APP_ADJ | 4 | 后台的重量级进程,system/rootdir/init.rc文件中设置 |
BACKUP_APP_ADJ | 3 | 备份进程 |
PERCEPTIBLE_APP_ADJ | 2 | 可感知进程(后台音乐、后台文件下载) |
VISIBLE_APP_ADJ | 1 | 可见进程 |
FOREGROUND_APP_ADJ | 0 | 前台进程 |
PERSISTENT_SERVICE_ADJ | -11 | 关联着系统或persistent进程 |
PERSISTENT_PROC_ADJ | -12 | 系统persistent进程,比如telephony |
SYSTEM_ADJ | -16 | 系统进程 |
NATIVE_ADJ | -17 | native进程,不受系统管理 |
OOM_ADJ>=4进程比较容易被杀死;
OOM_ADJ == [0,3] Android进程不容易被杀死
OOM_ADJ为负值表示非Android进程(纯Linux进程)。
在Lowmemorykiller回收内存时会根据进程的级别优先杀死OOM_ADJ比较大的进程,对于优先级相同的进程则进一步受到进程所占内存和进程存活时间的影响。
前台进程 Foreground process
用户当前操作所必须的进程,除非深度定制ROM、系统错误、内存不足才会杀死前台进程
(1)与用户正在交互的activity,调用onResume();
(2)持有一个Service,Service与正在交互的Activity绑定;
(3)持有一个Service,Service调用startForeground将其置为前台;
(4)持有一个Service,正在执行其生命周期回调(onCreate()、onStart() 或 onDestroy());
(5)持有一个正在执行onReceive()的BroadcastReceiver。
注意:
(1)优先级1表示最高级,普通进程的oom_adj>=0,系统进程oom_adj<0。
(2)系统会根据相应的内存阀值对符合某段oom_adj值的进程进行回收。
(3)oom_adj值也会随着占用物理内存越大而增大,系统进程绝对不会被系统杀死。
可见进程 Visible process
没有任何前台组件,不能与用户交互,但仍会影响用户在屏幕上所见内容的进程。
除非为了维持所有前台进程同时运行而必须终止,否则系统不会终止这些进程。
(1)持有不在前台、但仍对用户可见的 Activity,已调用onPause()。
(2)拥有绑定到可见或前台Activity / Service 的 Service。
服务进程 Service process
服务进程与用户所见内容没有直接关联,但是它们通常在执行一些用户关心的操作(例如,在后台播放音乐或从网络下载数据)。
除非内存不足以维持所有前台进程和可见进程同时运行,否则系统会让服务进程保持运行状态。
由startService()方法运行启动的Service属于服务进程。
后台进程 Background process
后台进程对用户体验没有直接影响,系统可能随时终止它们,以回收内存供前台进程、可见进程或服务进程使用。
对用户不可见的Activity的进程,已调用Activity的onStop()。
空进程 Empty process
保留这种进程的的唯一目的是用作缓存,以缩短下次在其中运行组件所需的启动时间。
为使总体系统资源在进程缓存和底层内核缓存之间保持平衡,系统往往会终止这些进程。
不含任何活动应用组件的进程
Android进程被杀的可能
进程杀死场景 | 调用的接口 | 可能的影响范围 |
---|---|---|
触发进程管理机制 | Lowmemorykiller | 从进程importance值由大到小依次杀死,释放内存 |
被第三方应用杀死(无Root) | killBackgroundProcess | 只能杀死OOM_ADJ>=4的进程 |
被第三方应用杀死(有Root) | force-stop或者kill | 理论上可以杀所有进程,一般只杀非系统关键进程、非前台、可见进程 |
用户主动"强行停止”进程 | force-stop | 只能停用第三方和非system/phone进程应用 |
进程提升优先级方案
由于知道Android进程被杀的场景,减少进程被杀死概率就是提高进程优先级,减少进程在内存不足等情况下被杀死的概率。
利用Activity提升权限
实现原理:监控手机锁屏解锁事件,在屏幕锁屏时启动1个像素的Activity,在用户解锁时将Activity销毁掉。
达成效果:将进程在锁屏期间的优先级由4变为1
应用场景:第三方应用及系统管理工具在检测到锁屏事件后一段时间(一般为5分钟以内)内会杀死后台进程,已达到省电的目的问题。
代码实现
1像素管理类ScreenManager.java
/**1像素管理类
*
* Created by jianddongguo on 2017/7/8.
*/
public class ScreenManager {
private static final String TAG = "ScreenManager";
private Context mContext;
private static ScreenManager mSreenManager;
// 使用弱引用,防止内存泄漏
private WeakReference<Activity> mActivityRef;
private ScreenManager(Context mContext){
this.mContext = mContext;
}
// 单例模式
public static ScreenManager getScreenManagerInstance(Context context){
if(mSreenManager == null){
mSreenManager = new ScreenManager(context);
}
return mSreenManager;
}
// 获得SinglePixelActivity的引用
public void setSingleActivity(Activity mActivity){
mActivityRef = new WeakReference<>(mActivity);
}
// 启动SinglePixelActivity
public void startActivity(){
if(Contants.DEBUG)
Log.d(TAG,"准备启动SinglePixelActivity...");
Intent intent = new Intent(mContext,SinglePixelActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
}
// 结束SinglePixelActivity
public void finishActivity(){
if(Contants.DEBUG)
Log.d(TAG,"准备结束SinglePixelActivity...");
if(mActivityRef != null){
Activity mActivity = mActivityRef.get();
if(mActivity != null){
mActivity.finish();
}
}
}
}
1像素的activity SinglePixelActivity.java
/**1像素Activity
*
* Created by jianddongguo on 2017/7/8.
*/
public class SinglePixelActivity extends AppCompatActivity {
private static final String TAG = "SinglePixelActivity";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(Contants.DEBUG)
Log.d(TAG,"onCreate--->启动1像素保活");
// 获得activity的Window对象,设置其属性
Window mWindow = getWindow(