应用场景:后台图片备份,息屏计步
应用在深圳知名大型互联公司,日活用户2000万
支持系统2.3到6.0
支持大部分设备,包括三星,华为,oppo,nexus,魅族等等
小米不行
进程优先级:
(1)什么时候系统会去杀死进程?
Android系统会在内存不足的时候去将进程杀死,俗称Low Memory Killer,它是 基于Linux内核的 OOM Killer(Out-Of-Memory killer)机制,内存不足时,优先杀oom_adj值高的进程。
既然知道了oom_adj值,那大家肯定想知道,如何去查看应用的oom_adj值呢?
系统进程oom值小于0,应用进程大于0,可以发现,系统的就是叼
我们可以通过 adb命令,去查看相应进程的oom_adj值,命令如下:
查看命令:adb shell ps | grep 进程名 | awk ‘{print $2}’ | xargs -i adb shell cat /proc/{}/oom_adj
Importance等级在ActivityManager.RunningAppProcessInfo中声明:
publicstaticclassRunningAppProcessInfoimplementsParcelable {/** * Constant for {@link #importance}: This process is running the * foreground UI; that is, it is the thing currently at the top of the screen * that the user is interacting with. */publicstaticfinalint IMPORTANCE_FOREGROUND = 100;
而adj值则在ProcessList中定义:
finalclassProcessList {// OOM adjustments for processes in various states:// Adjustment used in certain places where we don't know it yet.// (Generally this is something that is going to be cached, but we// don't know the exact value in the cached range to assign yet.)staticfinalint UNKNOWN_ADJ = 16;
Importance等级与adj值在ActivityManagerService中被关联起来,相较于Importance等级而言adj值可以赋予我们更多的参考价值
2.杀进程的各种方式和方法:
了解进程被杀死的相关场景后,相信大家对进程保活已经有了初步的认识,接下来我将给大家介绍一下,现在市面上存在的各种常见的保活拉起方式,这些保活方式如下:
**a) 将Service设置为前台服务
b) 在service的onstart方法里返回 STATR_STICK
c) 添加Manifest文件属性值为android:persistent=“true”
d) 覆写Service的onDestroy方法
e) 监听一堆系统静态广播
f) 监听第三方应用的静态广播
g) AlarmManager唤醒
h) 账户同步,定时唤醒
i) 1像素悬浮层
j) GCM或其它3方推送
k) 应用间互相拉起
l) 心跳唤醒
m)Native进程拉起
n) 双进程守护**-----靠谱
X).JobScheduler靠谱
1) 将Service设置为前台服务 :会有通知栏
思路:启用前台服务,主要是startForeground()
保活程度:一般情况下不被杀,部分定制ROM会在应用切到后台即杀
,会被 force stop 杀死
代码实现:
Notificationnotification = newNotification(R.drawable.queen2, "有消息来了"
, System.currentTimeMillis());
notification.setLatestEventInfo(this, "双11,上天猫!",
"一律5折", null);
//设置通知默认效果
notification.flags = Notification.FLAG_SHOW_LIGHTS;
startForeground(1, notification);
2) 在service的onstart方法里返回 STATR_STICK
START_STICKY:系统就会重新创建这个服务并且调用onStartCommand()方法,但是它不会重新传递最后的Intent对象,这适用于不执行命令的媒体播放器(或类似的服务),它只是无限期的运行着并等待工作的到来。
思路:其实就是onStartCommand中返回STATR_STICK
保活程度:有次数和时间的限制
,会被 force stop 杀死
代码实现:
@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {
// TODO Auto-generated method stubreturn START_STICKY;
//return super.onStartCommand(intent, flags, startId);
}
3) 添加Manifest文件属性值为android:persistent=“true”
如果你的应用能设置这个属性,可以全文跳过我这个系列所有文章。因为他真的可以杀不死,像系统的keyguard进程,media进程,且这些进程的adj都是负数,代表了前台activity黑屏了他们也不会死。但是这个属性需要系统shareuid,然后编译不过,因为需要系统签名,什么?你用系统签名?请忽略我全部
代码实现(清单文件中配置):
保活程度:一般情况下不被杀,会被 force stop 杀死
"PhoneApp"
android:persistent="true"
android:label="@string/dialerIconLabel"
android:icon="@drawable/ic_launcher_phone">
注意:该方法需要系统签名
4) 覆写Service的onDestroy方法
思路:在onDestroy中再次启动该服务
保活程度:很弱,只在两种情况下work:正在运行里杀服务、DDMS里stop进程 ,这个倒还算挺有效的一个方法,但是,直接干掉进程的时候,onDestroy()方法都进不来,更别想重启了
代码实现:
@Overridepublic void onDestroy() {
Intent intent = new Intent(this, KeeLiveService.class);
startService(intent);
super.onDestroy();
}
5) 监听一堆系统静态广播
思路:在发生特定系统事件时,系统会发出响应的广播,通过在 AndroidManifest 中“静态”注册对应的广播监听器,即可在发生响应事件时拉活。 在Android4.4以上,程序完全退出后,就不好接收广播了
可以监听的系统静态广播列表如下:
6) AlarmManager唤醒
思路:通过AlarmManager设置一个定时器,定时的唤醒服务
**保活强度:**killBackgroundProcess下,大部分情况work,
不敌force-stop,闹钟会被清除。
代码实现:
public void startKeepLiveService(Context context, int timeMillis,String action) {
//获取AlarmManager系统服务
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
//包装Intent
Intent intent = newIntent(context,KeepLiveServie.class);
intent.setAction(action);
PendingIntent pendingIntent = PendingIntent.getService(context,0,intent, PendingIntent.FLAG_UPDATE_CURRENT);
//添加到AlarmManager
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,System.currentTimeMillis(),timeMillis,pendingIntent);
}
7) 1像素悬浮层
**思路:**1像素悬浮层是传说的QQ黑科技,监控手机锁屏解锁事件,在屏幕锁屏时启动1个像素的 Activity,并设置透明,在用户解锁时将 Activity 销毁掉。注意该 Activity 需设计成用户无感知。通过该方案,可以使进程的优先级在屏幕锁屏时间由4提升为最高优先级1。
9) 应用间互相拉起
**思路:**app之间知道包名就可以相互唤醒了,比如你杀了我qq,只要微信还在就能确保随时唤醒qq。还有百度全系app都通过bdshare实现互拉互保,自定义一个广播,定时发,其他app收广播自起等
10) 心跳唤醒
思路:微信保活技术,依赖系统特性:长连接网络回包机制
保活强度:不敌force-stop,需要网络,API level >= 23的doze模式会关闭所有的网络
11)利用 JobScheduler 机制拉活
Android5.0 以后系统对 Native 进程等加强了管理,Native 拉活方式失效。系统在 Android5.0 以上版本提供了 JobScheduler 接口,系统会定时调用该进程以使应用进行一些逻辑操作。
12) Native进程拉起
留了一个别人的github链接,他里面的native保活实现方案也是大多数公司采用的方案。https://github.com/Coolerfall/Android-AppDaemon
原理:父进程和子进程,通过消息轮询的方式的不靠谱的,耗电
比较靠谱的原理:采用阻塞队列,系统忽略c进程的存在,通过C拉起java进程
思路:开启native子进程,定时发intent
保活强度:单杀可以杀死,force close 5.0以上无效,5.0以下部分手机无效,第三方软件下无效,且无法保证实时常驻
实现代码:
首先开启一个c进程,将需要保活的service名字传递进去
但这只是一个没有主的消息轮询器,说是守护其实很勉强,而且,这是要建立在保证c进程不挂的基础上,才能轮询,但是就目前来看,只有5.0以下的非国产机才会有这样的漏洞。也就是说在force close的时候,系统忽略c进程的存在,5.0以上包括5.0的哪怕源生系统也会连同c进程一起清理掉,国产机就更不用说了。就算是这样,在5.0以下的非国产机上,如果安装了获取root权限的360\cm的话,也是可以直接清理掉,也就是说会失效。
native进程守护缺点非常明显,那就是守护是单向的,也就是说只能a保b,b保不了a;a保b也不是在b死了立刻拉起来,要等到了时间才会去拉。那如何解决这个native进程的缺点呢?那就是通过双进程守护,下一篇我将详细讲解如何通过Linux层来实现双进程守护。
13.双进程守护。NDK来实现双进程保护的办法,不过首先说明一点
原理:
那么我们先来看看Android4.4的源码,ActivityManagerService(源码/frameworks放弃Java进程,使用两个纯native的binary进程,相互保活,确保native进程常驻,然后按时拉起需要常驻的java进程。在Linux下都是两个进程两个pid,但是在android系统的设置里面,父子进程中的native进程是android系统统计不到的
2个native之间的互拉通过,通过锁知道对方是否死了
主要的问题:2个进程之间的进程通信,用广播,启动service
我想到了文件锁。不论windows还是linux都会有一套文件的进程同步机制,为了各个进程间文件的同步问题,一个进程可以给一个文件上锁,操作完了之后再解锁,其他进程如果担心同步问题,会首先检查一下文件是否有锁,如果有锁,代表别人正在操作,就会延迟对文件的操作。那么当一个进程挂掉,他给文件加的锁也自然会消失。
/base/services/core/Java/com/Android/server/am/ActivityManagerService.java)是如何关闭在应用退出后清理内存的:
[java] view plain copy
应用退出后,ActivityManagerService就把主进程给杀死了,但是,在Android5.0中,ActivityManagerService却是这样处理的:
[java] view plain copy
虽只差了一句代码,差别却很大。Android5.0在应用退出后,ActivityManagerService不仅把主进程给杀死,另外把主进程所属的进程组一并杀死,这样一来,由于子进程和主进程在同一进程组,子进程在做的事情,也就停止了...要不怎么说Android5.0在安全方面做了很多更新呢...
再看看系统设置里面的force close(话说百分之九十五以上的应用都难逃系统的fc)是怎么杀掉进程的呢?
看到了吗?第一段注释,会杀掉所有和该packageName共享uid的进程,会取消掉该进程所有闹钟!
有没有办法让子进程脱离出来,不要受到主进程的影响
总结:线程组和闹钟都会被干掉,启用2Native个进程相互拉起,相互守护
5.0以下:用一个Native进程启动java进程
5.0以上和魅族手机:杀进程的方式修改了
要解决以上的问题
1.不被系统知道你的进程,用Native
2.2个进程怎么死了
3.2个进程之间的通信
小米搞不定
QQ为什么不会被杀死,是因为国内各大ROM不想让他死...
AS代码地址:不知道为什么上传不上