Android 永生不死的进程,进程守护,进程常驻,进程保活

应用场景:后台图片备份,息屏计步

应用在深圳知名大型互联公司,日活用户2000万

 

支持系统2.3到6.0

支持大部分设备,包括三星,华为,oppo,nexus,魅族等等

小米不行

进程优先级:

 

  1. 前台进程
  2. 可见进程
  3. 服务进程
  4. 后台进程
  5. 空进程

 

 

 

(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

这里我总结了各种类型进程的oom_adj值 
Android 永生不死的进程,进程守护,进程常驻,进程保活_第1张图片

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.杀进程的各种方式和方法:

3.常见的保活拉起方式

了解进程被杀死的相关场景后,相信大家对进程保活已经有了初步的认识,接下来我将给大家介绍一下,现在市面上存在的各种常见的保活拉起方式,这些保活方式如下:

**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);

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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">
  • 1
  • 2
  • 3
  • 4
  • 5

  • 1
  • 2
  • 3
  • 4
  • 5

注意:该方法需要系统签名

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以上,程序完全退出后,就不好接收广播了
可以监听的系统静态广播列表如下: 
Android 永生不死的进程,进程守护,进程常驻,进程保活_第2张图片

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  

  1. Process.killProcessQuiet(pid);  

应用退出后,ActivityManagerService就把主进程给杀死了,但是,在Android5.0中,ActivityManagerService却是这样处理的:

 

 

[java] view plain copy  

  1. Process.killProcessQuiet(app.pid);  
  2. Process.killProcessGroup(app.info.uid, app.pid);  

虽只差了一句代码,差别却很大。Android5.0在应用退出后,ActivityManagerService不仅把主进程给杀死,另外把主进程所属的进程组一并杀死,这样一来,由于子进程和主进程在同一进程组,子进程在做的事情,也就停止了...要不怎么说Android5.0在安全方面做了很多更新呢...

 

再看看系统设置里面的force close(话说百分之九十五以上的应用都难逃系统的fc)是怎么杀掉进程的呢?

Android 永生不死的进程,进程守护,进程常驻,进程保活_第3张图片

看到了吗?第一段注释,会杀掉所有和该packageName共享uid的进程,会取消掉该进程所有闹钟!

有没有办法让子进程脱离出来,不要受到主进程的影响

Android 永生不死的进程,进程守护,进程常驻,进程保活_第4张图片

 

总结:线程组和闹钟都会被干掉,启用2Native个进程相互拉起,相互守护

5.0以下:用一个Native进程启动java进程

5.0以上和魅族手机:杀进程的方式修改了

 

要解决以上的问题

1.不被系统知道你的进程,用Native

2.2个进程怎么死了

3.2个进程之间的通信

小米搞不定

 

QQ为什么不会被杀死,是因为国内各大ROM不想让他死...

 

AS代码地址:不知道为什么上传不上

 

 

 

 

你可能感兴趣的:(进程间的通讯)