前言

进程保活的关键点:

  1. 进程优先级, 优先级越高存活几率越大 。
  2. 弄清楚哪些场景会导致进程会 kill 。

所以,关键点在于提高进程的优先级在进程被 kill 之后能够唤醒

进程优先级

Android 一般的进程优先级划分:

  1. 前台进程 (Foreground process)
  2. 可见进程 (Visible process)
  3. 服务进程 (Service process)
  4. 后台进程 (Background process)
  5. 空进程 (Empty process)

    这是一种粗略的划分,进程其实有一种具体 的数值,称作 oom_adj,注意:数值越大优先级越低 。如何查看某个进程的 oom_adj 数值呢? oom_adj 存储在 proc/PID/oom_adj 文 件中,其中 PID 是进程的 id,直接 adb shell 进入手机根目录查看这个文件即可。

进程被 kill 的场景

点击 home 键使 app 长时间停留在后台,内存不足被 kill 。

处理这种情况前提是你的 app 至少运行了一个 service,然后通过Service.startForeground() 设置为前台服务,可以将 oom_adj 的数值由 4 降低到1,大大提高存活率。

  • 要注意的是 android4.3 之后 Service.startForeground() 会强制弹出通知栏,解决办法是再启动一个 service 和推送共用一个通知栏,然后 stop 这个 service。
  • Android 7.1 之后 google 修复这个 bug,目前没有解决办法 下面的代码 放到你的 service 的 onStartCommand 方法中:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //设置 service 为前台服务,提高优先级
    if (Build.VERSION.SDK_INT < 18) {
    //Android4.3 以下 ,此方法能有效隐藏 Notification 上的图标
    service.startForeground(GRAY_SERVICE_ID, new Notification());
    } else if(Build.VERSION.SDK_INT>18 && Build.VERSION.SDK_INT<25){
    //Android4.3 - Android7.0,此方法能有效隐藏 Notification 上的图标
    Intent innerIntent = new Intent(service, GrayInnerService.class);
    service.startService(innerIntent);
    service.startForeground(GRAY_SERVICE_ID, new Notification());
    }else{
    //Android7.1 google 修复了此漏洞,暂无解决方法(现状:Android7.1 以上
    app 启动后通知栏会出现一条"正在运行"的通知消息)
    service.startForeground(GRAY_SERVICE_ID, new Notification());
    }

在大多数国产手机下,进入锁屏状态一段时间,省电机制会 kill 后台进程。

这种情况和上面不太一样,是很过国产手机 rom 自带的优化,当锁屏一段时间之后,即使手机内存够用为了省电,也会释放掉一部分内存。
策略:注册广播监听锁屏和解锁事件, 锁屏后启动一个 1 像素的透明 Activity,这样直接把进程的 oom_adj 数值降低到 0,0 是 android 进程的最高优先级。解锁后销毁这个透明 Activity。这里我把这个 Activity 放到:remote 进程也就是我那个后台服务进程,当然你也可以放到主进程,看你打算保活哪个进程。

用户手动释放内存:包括手机自带清理工具,和第三方 app(360,猎豹清理大师等)

清理内存软件会把 优先级低于 前台进程(oom_adj = 0)的所有进程放入清理列表,而当我们打开了清理软件就意味着其他 app 不可能处于前台。所以说理论上可以 kill 任何 app。
因此这类场景唯一的处理办法就是加入 手机 rom 白名单,比如你打开小米,魅族的权限管理 -> 自启动管理可以看到 QQ,微信,天猫默认被勾选,这就是厂商合作。