Android进程保活
一、优先级
进程的重要性优先级:(越往后的就越容易被系统杀死) 1.前台进程;Foreground process 1)用户正在交互的Activity(onResume()) 2)当某个Service绑定正在交互的Activity。 3)被主动调用为前台Service(startForeground()) 4)组件正在执行生命周期的回调(onCreate()/onStart()/onDestroy()) 5)BroadcastReceiver 正在执行onReceive();
2.可见进程;Visible process 1)我们的Activity处在onPause()(没有进入onStop()) 2)绑定到前台Activity的Service。
3.服务进程;Service process 简单的startService()启动。 4.后台进程;Background process 对用户没有直接影响的进程----Activity出于onStop()的时候。 android:process=":xxx" 5.空进程; Empty process 不含有任何的活动的组件。(android设计的,为了第二次启动更快,采取的一个权衡)
二、如何提升进程的优先级(尽量做到不轻易被系统杀死)
1.QQ采取在锁屏的时候启动一个1个像素的Activity,当用户解锁以后将这个Activity结束掉(顺便同时把自己的核心服务再开启一次)。被用户发现了就不好了。 故事:小米撕逼。 背景:当手机锁屏的时候什么都干死了,为了省电。 锁屏界面在上面盖住了。 监听锁屏广播,锁了---启动这个Activity。 监听锁屏的, 开启---结束掉这个Activity。 要监听锁屏的广播---动态注册。 ScreenListener.begin(new xxxListener onScreenOff() );
被系统无法杀死的进程。
2.app运营商和手机厂商可能有合作关系---白名单。
3.双进程守护---可以防止单个进程杀死,同时可以防止第三方的360清理掉。 一个进程被杀死,另外一个进程又被他启动。相互监听启动。 A<--->B 杀进程是一个一个杀的。本质是和杀进程时间赛跑。
4.JobScheduler 把任务加到系统调度队列中,当到达任务窗口期的时候就会执行,我们可以在这个任务里面启动我们的进程。 这样可以做到将近杀不死的进程。
5.监听QQ,微信,系统应用,友盟,小米推送等等的广播,然后把自己启动了。
6.利用账号同步机制唤醒我们的进程
AccountManager
7.NDK来解决,Native进程来实现双进程守护。
Android 进程拉活包括两个层面:
A. 提供进程优先级,降低进程被杀死的概率
B. 在进程被杀死后,进行拉活
利用 Activity 提升权限
方案设计思想
监控手机锁屏解锁事件,在屏幕锁屏时启动1个像素的 Activity,在用户解锁时将 Activity 销毁掉。注意该 Activity 需设计成用户无感知。
通过该方案,可以使进程的优先级在屏幕锁屏时间由4提升为最高优先级1。
方案适用范围
适用场景: 本方案主要解决第三方应用及系统管理工具在检测到锁屏事件后一段时间(一般为5分钟以内)内会杀死后台进程,已达到省电的目的问题。
适用版本
适用于所有的 Android 版本。但是小米之前已经干掉了这种可能。
具体代码参看上面链接
利用 Notification 提升权限
方案设计思想
Android 中 Service 的优先级为4,通过 setForeground 接口可以将后台 Service 设置为前台 Service,使进程的优先级由4提升为2,从而使进程的优先级仅仅低于用户当前正在交互的进程,与可见进程优先级一致,使进程被杀死的概率大大降低。
方案实现挑战
从 Android2.3 开始调用 setForeground 将后台 Service 设置为前台 Service 时,必须在系统的通知栏发送一条通知,也就是前台 Service 与一条可见的通知时绑定在一起的。
对于不需要常驻通知栏的应用来说,该方案虽好,但却是用户感知的,无法直接使用。
方案挑战应对措施
通过实现一个内部 Service,在 LiveService 和其内部 Service 中同时发送具有相同 ID 的 Notification,然后将内部 Service 结束掉。随着内部 Service 的结束,Notification 将会消失,但系统优先级依然保持为2。
以上利用 Activity 提升权限和利用 Notification 提升权限都是提升进程优先级的方案。
下面看一下进程死后拉活的方案
利用系统广播拉活
在发生特定系统事件时,系统会发出响应的广播,通过在 AndroidManifest 中“静态”注册对应的广播监听器,即可在发生响应事件时拉活。
但是,这些广播逐渐被Android给限制一些条件才能使用,例如启动手机广播,网络切换广播,并不是说要禁止,而是如果你在接收这些广播的时间,应用不在前台就无法收到。这就避免了用它来拉活的概念。
方案适用范围
适用于全部 Android 平台。但存在如下几个缺点:
1) 广播接收器被管理软件、系统软件通过“自启管理”等功能禁用的场景无法接收到广播,从而无法自启。
2) 系统广播事件不可控,只能保证发生事件时拉活进程,但无法保证进程挂掉后立即拉活。
因此,该方案主要作为备用手段。
利用第三方应用广播拉活
方案设计思想
该方案总的设计思想与接收系统广播类似,不同的是该方案为接收第三方 Top 应用广播。
通过反编译第三方 Top 应用,如:手机QQ、微信、支付宝、UC浏览器等,以及友盟、信鸽、个推等 SDK,找出它们外发的广播,在应用中进行监听,这样当这些应用发出广播时,就会将我们的应用拉活。
方案适用范围
该方案的有效程度除与系统广播一样的因素外,主要受如下因素限制:
1) 反编译分析过的第三方应用的多少
2) 第三方应用的广播属于应用私有,当前版本中有效的广播,在后续版本随时就可能被移除或被改为不外发。
这些因素都影响了拉活的效果。
利用系统Service机制拉活
方案设计思想
将 Service 设置为 START_STICKY,利用系统机制在 Service 挂掉后自动拉活:
方案适用范围
如下两种情况无法拉活:
Service 第一次被异常杀死后会在5秒内重启,第二次被杀死会在10秒内重启,第三次会在20秒内重启,一旦在短时间内 Service 被杀死达到5次,则系统不再拉起。
进程被取得 Root 权限的管理工具或系统工具通过 forestop 停止掉,无法重启。
利用Native进程拉活
方案设计思想
主要思想:利用 Linux 中的 fork 机制创建 Native 进程,在 Native 进程中监控主进程的存活,当主进程挂掉后,在 Native 进程中立即对主进程进行拉活。
主要原理:在 Android 中所有进程和系统组件的生命周期受 ActivityManagerService 的统一管理。而且,通过 Linux 的 fork 机制创建的进程为纯 Linux 进程,其生命周期不受 Android 的管理。
方案实现挑战
挑战一:在 Native 进程中如何感知主进程死亡。
要在 Native 进程中感知主进程是否存活有两种实现方式:
在 Native 进程中通过死循环或定时器,轮训判断主进程是否存活,档主进程不存活时进行拉活。该方案的很大缺点是不停的轮询执行判断逻辑,非常耗电。
在主进程中创建一个监控文件,并且在主进程中持有文件锁。在拉活进程启动后申请文件锁将会被堵塞,一旦可以成功获取到锁,说明主进程挂掉,即可进行拉活。由于 Android 中的应用都运行于虚拟机之上,Java 层的文件锁与 Linux 层的文件锁是不同的,要实现该功能需要封装 Linux 层的文件锁供上层调用。
挑战二:在 Native 进程中如何拉活主进程。
通过 Native 进程拉活主进程的部分代码如下,即通过 am 命令进行拉活。通过指定“–include-stopped-packages”参数来拉活主进程处于 forestop 状态的情况。
挑战三:如何保证 Native 进程的唯一。
从可扩展性和进程唯一等多方面考虑,将 Native 进程设计层 C/S 结构模式,主进程与 Native 进程通过 Localsocket 进行通信。在Native进程中利用 Localsocket 保证 Native 进程的唯一性,不至于出现创建多个 Native 进程以及 Native 进程变成僵尸进程等问题。
方案适用范围
该方案主要适用于 Android5.0 以下版本手机。
该方案不受 forcestop 影响,被强制停止的应用依然可以被拉活,在 Android5.0 以下版本拉活效果非常好。
对于 Android5.0 以上手机,系统虽然会将native进程内的所有进程都杀死,这里其实就是系统“依次”杀死进程时间与拉活逻辑执行时间赛跑的问题,如果可以跑的比系统逻辑快,依然可以有效拉起。记得网上有人做过实验,该结论是成立的,在某些 Android 5.0 以上机型有效。
利用账号同步机制拉活
方案设计思想
Android 系统的账号同步机制会定期同步账号进行,该方案目的在于利用同步机制进行进程的拉活。
方案适用范围
该方案适用于所有的 Android 版本,包括被 forestop 掉的进程也可以进行拉活。
最新 Android 版本(Android N)中系统好像对账户同步这里做了变动,该方法不再有效。
其他有效拉活方案
经研究发现还有其他一些系统拉活措施可以使用,但在使用时需要用户授权,用户感知比较强烈。
这些方案包括:
利用系统通知管理权限进行拉活
利用辅助功能拉活,将应用加入厂商或管理软件白名单。
这些方案需要结合具体产品特性来搞。
上面所有解释这些方案都是考虑的无 Root 的情况。
其他还有一些技术之外的措施,比如说应用内 Push 通道的选择:
国外版应用:接入 Google 的 GCM。
国内版应用:根据终端不同,在小米手机(包括 MIUI)接入小米推送、华为手机接入华为推送;其他手机可以考虑接入腾讯信鸽或极光推送与小米推送做 A/B Test。
应用被杀掉后,收不到push怎么办
首先,要明白什么是杀死:
普通清理,该清理软件没有系统权限,也没有获得该手机的Root权限,那么它只能杀死进程。如果这个进程里面的service有onStartCommand的START_STICKY,那么重启没有问题。
Force Stopped清理,这种清理软件一般是系统自带或者是获得了Root权限的清理方法(现在大多数清理软件在获取Root权限后都有这个功能),这个清理其实是杀死进程并且把应用置为睡眠状态,如果应用处于这个状态,那么它是不可能用上面的方法被唤醒。(注:这个Force Stopped仅仅对有界面的应用才可行,如果没有界面,它是无用的,只能被杀死进程,而不能被置为stopped状态,这点至关重要),最为关键的是处于这个状态的接收不了被注册的静态广播,除非广播里面有include_stopped_package这个标识。
上面所有方案中:NDK双进程不受 forcestop 影响,被强制停止的应用依然可以被拉活,在 Android5.0 以下版本拉活效果非常好
唤起应用方案:
一、如果是普通被杀死,用Android自身的机制就没有问题。
二、如果是Force Stopped,那么它接收不了广播,无法自动唤醒,只能依赖第三方。
1、做一个无界面应用,接收stopped静态广播,不幸的是,在国内,这个被置为stopped的静态广播被阉割掉了,三星还有。 2、因为个推这些第三方push做了互推的功能,你虽然把所有的进程都杀了,如果你打开其中一个个推的应用,那么它会 发消息把接了个推的全部唤醒。 3、利用第二点的特性,我们把各个厂家接受的注册代码都在自己的里面注册一下(灵感:把所有的push平台接一遍,完全 没有必要),这样可以充分利用各家的相互唤醒功能。 4、对小米,可以直接接个小米推送,或者用一个接收代码(当它打开其它有小米推送的应用时,可以被唤起)
今日头条、虎扑接了小米的推送,即使在被Force Stopped之后还能被小米自己的推送给唤醒。 喜马拉雅拉了百度推送和个推,百度推送没什么用处,不过启动一个集成了个推的app 就会把一个手机上凡是接了个推的全部起来。
测试: 环境:红米1S或其它普通手机 1、安装几个含有个推的app,然后全部杀死。 2、观看进程,启动其中一个app,看看其它会不会起来。(要锁屏再打开,会直接启动其它兄弟产品)
针对特殊机型: 环境:小米和华为 这个在被Force Stopped之后是不能被重启的,除非你接了小米自身的推送。 今日头条、虎扑就是这个情况,它的进程虽然被关了,但是如果有推送就会被唤起。
白名单问题: 微信、QQ这些应用都是被加入白名单的,各家安全软件在对其一键清理的时间并不会清理它,并非技术层面, 而是通过商务合作,通过ps查看还有qihoo360这些软件也在MIUI的一键清理之外。
解决方案: 1、把微博通过商务合作做成免杀,然后通过微博去唤起自己的兄弟产品。 2、接小米推送
Last updated