本专栏专一分享大型Bat面试知识,后续会持续更新,喜欢的话麻烦点击一个关注
进程保活的关键点有两个,一个是进程优先级的理解,优先级越高存活概率越大。二是弄清楚哪些场景会致使进程会kill,而后采起下面的策略对各类场景进行优化:android
废话很少说先上面试资料目录面试
Android通常的进程优先级划分: 1.前台进程 (Foreground process) 2.可见进程 (Visible process) 3.服务进程 (Service process) 4.后台进程 (Background process) 5.空进程 (Empty process) 这是一种粗略的划分,进程其实有一种具体的数值,称做oom_adj,注意:数值越大优先级越低:shell
如何查看某个进程的oom_adj数值呢? oom_adj 存储在proc/PID/oom_adj文件中,其中PID是进程的id,直接 adb shell进入手机根目录查看这个文件便可。api
演示一下:以我本身的项目为例,app中有两个进程,一个是主进程,另外一个是运行service的进程取名为:remote。首先用android studio查看每一个进程的PID:
而后分别查看app在前台,app退到后台,这2中场景主进程的oom_adj数值:
可见,当app在前台时 oom_adj = 0,对应上面的表格是前台进程。安全
当app退到后台时,oom_adj = 6,对应后台进程。微信
而后查看运行着service的进程:
ok,知道了进程优先级的概念以及如何查看优先级,咱们就能够对app进程优化,而后经过查看这个数值判断咱们的优化是否有效果。app
1.点击home键使app长时间停留在后台,内存不足被killide
处理这种状况前提是你的app至少运行了一个service,而后经过Service.startForeground() 设置为前台服务,能够将oom_adj的数值由4下降到1,大大提升存活率。工具
//设置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()); }
通过改进以后,再来看下这个后台service进程的oom_adj,发现被提高为前台进程。测试
2.在大多数国产手机下,进入锁屏状态一段时间,省电机制会kill后台进程
这种状况和上面不太同样,是很过国产手机rom自带的优化,当锁屏一段时间以后,即便手机内存够用为了省电,也会释放掉一部份内存。
策略:注册广播监听锁屏和解锁事件, 锁屏后启动一个1像素的透明Activity,这样直接把进程的oom_adj数值下降到0,0是android进程的最高优先级。 解锁后销毁这个透明Activity。这里我把这个Activity放到:remote进程也就是我那个后台服务进程,固然你也能够放到主进程,看你打算保活哪一个进程。
咱们能够写一个KeepLiveManager来负责接收广播,维护这个Activity的常见和销毁,注意锁屏广播和解锁分别是:ACTION_SCREEN_OOF和ACTION_USER_PRESENT,而且只能经过动态注册来绑定,而且是绑定到你的后台service里面,onCreate绑定,onDestroy里面解绑
配好以后把手机锁屏,看下:remote进程的oom_adj:
3. 用户手动释放内存:包括手机自带清理工具,和第三方app(360,猎豹清理大师等)
清理内存软件会把 优先级低于 前台进程(oom_adj = 0)的全部进程放入清理列表,而当咱们打开了清理软件就意味着其余app不可能处于前台。因此说理论上能够kill任何app。 以360安全卫士为例,打开内存清理:
所以这类场景惟一的处理办法就是加入 手机rom 白名单,好比你打开小米,魅族的权限管理 -> 自启动管理能够看到 QQ,微信,天猫默认被勾选,这就是厂商合做。那咱们普通app能够这么作:在app的设置界面加一个选项,提示用户本身去勾选自启动,我封装了一个工具类给出国内各厂商的自启动的Intent跳转方法:
/** * Created by carmelo on 2018/3/17. * 国内手机厂商白名单跳转工具类 */ public class SettingUtils { public static void enterWhiteListSetting(Context context){ try { context.startActivity(getSettingIntent()); }catch (Exception e){ context.startActivity(new Intent(Settings.ACTION_SETTINGS)); } } private static Intent getSettingIntent(){ ComponentName componentName = null; String brand = android.os.Build.BRAND; switch (brand.toLowerCase()){ case "samsung": componentName = new ComponentName("com.samsung.android.sm", "com.samsung.android.sm.app.dashboard.SmartManagerDashBoardActivity"); break; case "huawei": componentName = new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity"); break; case "xiaomi": componentName = new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity"); break; case "vivo": componentName = new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity"); break; case "oppo": componentName = new ComponentName("com.coloros.oppoguardelf", "com.coloros.powermanager.fuelgaue.PowerUsageModelActivity"); break; case "360": componentName = new ComponentName("com.yulong.android.coolsafe", "com.yulong.android.coolsafe.ui.activity.autorun.AutoRunListActivity"); break; case "meizu": componentName = new ComponentName("com.meizu.safe", "com.meizu.safe.permission.SmartBGActivity"); break; case "oneplus": componentName = new ComponentName("com.oneplus.security", "com.oneplus.security.chainlaunch.view.ChainLaunchAppListActivity"); break; default: break; } Intent intent = new Intent(); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if(componentName!=null){ intent.setComponent(componentName); }else{ intent.setAction(Settings.ACTION_SETTINGS); } return intent; } }
补充几点:
在酷安应用市场下载一个叫 当前Activity 的app,打开后能够看到当前界面的className,例如:
就找到了魅族MX4 pro 后台权限的Activity。
分两种状况,一是主进程(含有Activity没有service),这种进程因为内存不足被kill以后,用户再次打开app系统会恢复到上次的Activity,这个不在本文话题以内。另外一种是service的后台进程被kill,能够经过service自有api来重启service:
@Override public int onStartCommand(Intent intent, int flags, int startId) { //..... return START_STICKY; // service被异常中止后,系统尝试重启service,不能保证100%重启成功 }
配好START_STICKY后,经过android studio 释放进程的工具测试下,能够发现:remote进程被kill以后立刻重启了:
但它不是100%保证重启成功,好比下面2种状况:(本人通过测试,这里就不放效果图了)
本文经过两种 提升进程优先级的方法,针对锁屏 和非锁屏模式下进程在后台被kill的场景处理,把后台进程优先级提高到可见级别,基本能够保证绝大多数场景不会被kill。另外,针对含有service的进程被kill给出了可唤醒的办法。
须要进程保活的代码+开头面试资料+以下视频资料的能够加
QQ群:892872246