保活手段
当前业界的Android进程保活手段主要分为黑、白、灰三种,其大致的实现思路如下:
黑色保活:
不同的app进程,用广播相互唤醒(包括利用系统提供的广播进行唤醒)
白色保活:
启动前台Service(体验不太好)
灰色保活:
利用系统的漏洞启动前台Service
黑色保活
所谓黑色保活,就是利用不同的app进程使用广播来进行相互唤醒。举个3个比较常见的场景:
场景1:
开机,网络切换、拍照、拍视频时候,利用系统产生的广播唤醒app(Google陆续取消了这部分的系统广播)
场景2:
接入第三方SDK也会唤醒相应的app进程,如微信sdk会唤醒微信,支付宝sdk会唤醒支付宝。由此发散开去,就会直接触发了下面的 场景3
场景3:
假如你手机里装了支付宝、淘宝、天猫、UC等阿里系的app,那么你打开任意一个阿里系的app后,有可能就顺便把其他阿里系的app给唤醒了。(导致手机很卡)
白色保活
就是调用系统api启动一个前台的Service进程,这样会在系统的通知栏生成一个Notification,用来让用户知道有这样一个app在运行着,哪怕当前的app退到了后台
缺个图片
灰色保活
灰色保活,这种保活手段是应用范围最广泛。它是利用系统的漏洞来启动一个前台的Service进程,与普通的启动方式区别在于,它不会在系统通知栏处出现一个Notification,看起来就如同运行着一个后台Service进程一样。这样做带来的好处就是,用户无法察觉到你运行着一个前台进程(因为看不到Notification),但你的进程优先级又是高于普通后台进程的。那么如何利用系统的漏洞呢,大致的实现思路和代码如下:
思路一:
API < 18,启动前台Service时直接传入new Notification();
思路二:
API >= 18,同时启动两个id相同的前台Service,然后再将后启动的Service做stop处理;
public class GrayService extends Service {
private final static int GRAY_SERVICE_ID = 1001;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (Build.VERSION.SDK_INT < 18) {
startForeground(GRAY_SERVICE_ID, new Notification());//API < 18 ,此方法能有效隐藏Notification上的图标
} else {
Intent innerIntent = new Intent(this, GrayInnerService.class);
startService(innerIntent);
startForeground(GRAY_SERVICE_ID, new Notification());
}
return super.onStartCommand(intent, flags, startId);
}
...
...
/**
* 给 API >= 18 的平台上用的灰色保活手段(静态内部类)
*/
public static class GrayInnerService extends Service {
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
startForeground(GRAY_SERVICE_ID, new Notification());
stopForeground(true);
stopSelf();
return super.onStartCommand(intent, flags, startId);
}
}
}
其他拉活方法
利用系统Service机制拉活
如下两种情况无法拉活:
Service 第一次被异常杀死后会在5秒内重启,第二次被杀死会在10秒内重启,第三次会在20秒内重启,一旦在短时间内 Service 被杀死达到5次,则系统不再拉起。
进程被取得 Root 权限的管理工具或系统工具通过 forestop 停止掉,无法重启。
利用Native进程拉活
该方案主要适用于 Android5.0 以下版本手机。
该方案不受 forcestop 影响,被强制停止的应用依然可以被拉活,在 Android5.0 以下版本拉活效果非常好。
对于 Android5.0 以上手机,系统虽然会将native进程内的所有进程都杀死,这里其实就是系统“依次”杀死进程时间与拉活逻辑执行时间赛跑的问题,如果可以跑的比系统逻辑快,依然可以有效拉起。记得网上有人做过实验,该结论是成立的,在某些 Android 5.0 以上机型有效。
总结
上面所提到的保活不是真正的让线程不死,而只是让线程的重要优先级提高,难以被杀死,杀进程回收内存的机制就叫 Low Memory Killer。LMB会根据oom_adj的值来选择是否优先杀死。oom_adj是linux内核分配给每个系统进程的一个值,代表进程的优先级,越大越容易被杀死。(可以通过adb shell和线程ID来获得这个oom_adj)
- 普通app进程的oom_adj>=0,系统进程的oom_adj才可能<0
- 有些手机厂家会把一些常用的app加入自己定制的Android版本的白名单里,通过让这些app的oom_adj与系统进程一样,来提高用户体验
最后提一下,保活会造成android生态的混乱,可能会造成有些本来应该存在的线程被无关紧要的线程通过保活的手段顶掉。。大家都不想死,但是内存不足的时候还不是要死,所以保活让线程不死是个伪命题,最后还是要从对应用的内存优化控制来下手。
转自作者:D_clock爱吃葱花
链接:https://www.jianshu.com/p/63aafe3c12af
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
201907301711编辑:查看oom_adjhttps://blog.csdn.net/simon_yds/article/details/78607193