进程保活介绍

进程保活

进程保活

进程保活的方式分为两个层面:提高进程优先级,降低被杀死的概率,在进程被杀死后,进行拉活

1. 进程的优先级

进程优先级

优先级最低的进程首先被杀死、进程的等级会因为其他进程的依赖而提高一个进程服务于另一个进程,则它的优先级不会比它服务的进程优先级低

按重要性分类:

  • 前台进程:进程持有一个正在与用户交互的Activity或者和交互Activity绑定的Service,前台运行的Service(执行startForeground()),执行onReceive()的BroadcastReceiver
  • 可见进程:进程持有一个被用户可见但没有显示在最前端的Activity(调用到了onPause())或者和可见Activity绑定的Service
  • 服务进程:进程持有一个startService()启动的Service进程,例如播放音乐,下载文件等Service
  • 后台进程:进程持有一个用户不可见的Activity(调用到onStop()没有到onDestroy()),进程被存放在一个LRU列表中,即很长时间没用的Activity会被优先杀死
  • 空进程:进程不包含任何活跃的应用组件,唯一的作用是为了缓存需要,缩短下次启动的时间

2. Android进程回收策略

对于进程的回收,依靠LowmemoryKiller完成,按照OOM_ADJ的阈值级别触发对应的内存回收。

进程级别

红色代表易被杀死的进程,绿色不易被杀死。LowmemoryKiller会优先杀死OOM_ADJ较大的进程,优先级相同则进一步受到进程所占内存和进程存活时间的影响。

3. 提升进程优先级

  • 利用Activity提升权限监控手机锁屏解锁事件,在屏幕锁定时启动一个一像素的Activity,解锁时销毁。需把Activity设置成用户无感知
  • 利用Notification提升权限Service的优先级为4,使用setForeground可以设置前台Service,提升进程的优先级,降低被杀的概率。
    • 注意点:设置为前台Service时,在通知栏会显示一条通知。
    • 应对措施:可以去实现一个内部Service,在LiveService和其内部Service中同时发送相同ID的Notification,然后结束内部Service。内部Service被结束时,Notification也会消失,但是进程的优先级不会发生变化。

4. 进程死后拉活的方案

  • 利用系统广播拉活:在发生特定事件是,系统会发送相应的广播,可以在AndroidManifest中静态注册对应的广播监听器,即可在对应事件发生时拉活应用。以下是常见的拉活广播事件:
    • 开机广播:RECEIVE_BOOT_COMPLETED
    • 网络变化:CHANGE_NETWORK_STATE,CHANGE_WIFI_STATE…
    • 文件挂载:MOUNT_UNMOUNT_FILESYSTEMS
    • 屏幕亮灭:SCREEN_ON,SCREEN_OFF
    • 锁屏解锁:RECEIVE_USER_PRESENT
    • 应用安装卸载:PACKAGE_ADDED,PACKAGE_REMOVED
      缺点:
    • 广播接收器容易被系统的管理软件通过“自启管理”禁用场景,从而无法处理
    • 系统广播事件不可控,只能保证有对应事件是拉活进程,但不能保证能否立即拉活。
  • 利用第三方应用广播拉活:该方案接受第三方应用的广播,反编译一些第三方应用,找到他们发送的广播,在自己应用内进行监听,当这些应用发送广播时,即可拉活自己的应用。
    缺点:
    • 需要反编译较多应用来确保效果
    • 第三方应用的广播可能会在日后更新中修改或删除
  • 利用系统Service机制拉活:把Service设置为START_STICKY,这个参数可以在Service被杀死后,利用系统机制尝试拉活。
    缺点:
    • Service第一次被异常杀死后会在5秒内重启,第二层被杀死10秒内重启,第三次会在20秒内重启,一旦被杀死达到5次,则系统不会再重新拉活。
    • 进程被Root权限的工具杀死活forcestop,无法重启。
  • 利用Native进程拉活:利用Linux中的fork机制创建Native进程,在Native进程中监控主进程的存活,当主进程挂掉后,在Native进程中立即对主进程拉活。(该进程的生命周期不受Android的管理)。
    适用范围:
    • 在Android5.0以下版本手机效果很好,不受forcestop影响
    • 在5.0以上的手机,Native进场也会被forcestop杀死,假如逻辑跑的比系统快,依然可以拉活。
  • 利用JobScheduler机制拉活:系统在Android5.0以上版本提供了JobScheduler接口,系统会定时调用该进程使应用处理一些操作。
    适用范围:Android5.0以上系统手机,在部分小米手机可能无法拉活。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public class KeepLiveService extends JobService {

    private final static String TAG="KeepLive";

    private volatile static Service mKeepLiveService= null;

    @Override
    public boolean onStartJob(JobParameters jobParameters) {
    return false;
    }

    @Override
    public boolean onStopJob(JobParameters jobParameters) {
    return false;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public void startJobscheduler(){
    try {
    int jobId=1;
    JobInfo.Builder builder=new JobInfo.Builder(jobId,
    new ComponentName(MyApplication.getApplicationContext(),
    KeepLiveService.class));
    builder.setPeriodic(10);//设置时间间隔
    builder.setPersisted(true);//重启后需要继续执行
    JobScheduler js = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
    js.schedule(builder.build());
    }catch (Throwable e){
    e.printStackTrace();
    }
    }
  • 利用账号同步进制拉活:Android系统的账号同步进制会定期同步执行,可以利用同步机制进行进程的拉活。
    适用范围:适用于所有的Android版本,在Android N中进行了一些变动,该方案失效。

  • 其他方案
    • 利用系统通知权限进行拉活
    • 利用辅助功能拉活,将应用加入厂商白名单
    • 利用推送进行拉活(如小米、华为推送)