(4.6.17)进程保活(概念):为什么要进程保活或进程常驻

来源:互联网 发布:网络信息的利与弊图片 编辑:程序博客网 时间:2024/04/25 15:03

Android 进程常驻(1)----开篇


Android 进程常驻,顾名思义,就是要让我们的进程在内存中永远存在,换句话说就是进程保活,臭不要脸的说法就是关不了,杀不死,干不掉。这不是耍流氓,是很多场景如果要想为用户服务,就必须有一个进程常驻,以便在特定的时候做特定的事情。比如在Android中,许多BroadcastReceiver事件不支持静态注册,也就是说如果我想接受屏幕开关的系统广播,必须要在进程中动态注册,如果没有一个常驻进程,那么锁屏应用就无法正常为用户服务;另外IM类应用,也需要在后台维护一个长链接,以便于在最及时的时间里将信息传达给用户。诚然,但凡进程常驻内存,无论怎样优化,都会或多或少的增加一些额外的性能开支,在为用户最负责任的服务,最高品质的体现我们的价值的前提下,我们要尽可能减少内存和电量的消耗,这个后面会说到。这里吐槽一下一些无良开发者,为一些完全不必要的业务常驻一个进程,这样只会加快用户卸载的速度,最让人忍受不了的是,代码低效,保活无力,还特么烧电!最后我想说的是,不以服务用户为目的的内存常驻都是耍流氓!

闲淡少扯。

进入正题。

知己知彼,方能百战不殆。要想保活,就要先知道是怎么死的。死因大概有三:第一被系统干死;第二被第三方安全软件干死,比如知名的有奇虎360、CleanMaster(当然包括是否有root权限,有无root天壤之别);第三就是被用户手动干死,比如小米自带的系统一键清理、手机设置里应用管理器的ForceClose。下面开始分析。

Android系统是基于Linux系统,他继承了Linux的内存管理策略,即进程退出并不会立刻杀死,而是在系统内存吃紧的时候再来按照优先级杀掉进程,这不同于微软的Windows,Windows在进程退出的同时一定杀掉进程,将内存释放干净。一个是尽可能的充分利用内存,来提高再次开启进程的速度;一个是放着大块大块的内存宁可永远闲置也不用。作为一个移动设备的操作系统,Android继承前者无可厚非,他继承了Linux的lowmemorykiller。

在系统的/sys/module/lowmemorykiller/parameters目录下,我们cat文件minfree,他记录了6个数字,分别对应了六个进程类型的斩首的阀值(单位为page,1page=4kb)。如图


(三星note3)

(三星s5


六个进程类型从左往右分别为:ForegroundProgress/VisibleProgress/SecondaryService/HiddenProgress/ContentProvider/EmptyProgress

1、前台进程(比如正在显示的activity所在的进程)

2、可见进程(比如输入法进程)

3、次要服务进程

4、隐藏进程

5、内容提供者进程

6、空进程

这些数字所代表到所谓斩首阀值,代表系统剩余内存达到他们对应的阀值的时候,就开始操刀斩首对应的进程了,所以在上图可以看出,当s5剩余内存为56320*4kb约等于200m的时候开始清理空进程,而note3则是120m才开始。


六个进程类型定义于kernel层,在framework层,做了更细致的划分,以便于进程查看管理。他们定义在com.android.server.am.ActivityManager.RunningProgressInfo中,如下图。开发者可以使用Android 开放的API拿到对应进程的RunningProgressInfo来查看他的importance。




当斩首开始,同样一个级别的进程有好多个,究竟先杀谁呢?比比谁的哈希值大就先杀谁?当然不是。Kernel层定义了六个进程类型对应的adj,他们定义在/sys/module/lowmemorykiller/parameters/adj


数值越大越容易被杀,同时Android 增加了两个Linux中没有的进程adj,他们分别是CORE_SERVER_ADJ=-12、SYSTEM_ADJ = -16,定义在ActivityManagerService中。我们可以在在shell下ps查看所有进程,找到对应进程pid,然后再/proc/pid/oom_adj下查看对应进程的adj。


上图是在手机三星s5上,系统为android5.1,应用中在MainActivity启动了两个Service,并且两个Service 都在menifest中定义为其他进程


从上到下分别为activity的进程,正常的service进程,设置为前台service的service进程。

然后分别到对应的进程号pid的目录下查看对应的adj。

每次cat都对应了ui上的操作:

从上往下分别是:

应用安装完毕,5.1系统会弹出一个activity来确认应用权限,此时我们的activity为onstrop状态(5114进程第一次cat)

关闭权限确认的界面,此时我们的activity为onresume状态(5114进程第二次cat)

点击back键,我们的activity为ondestroy状态,且该进程内无其他运行组件(5114进程第三次cat)

正常的service进程,没有做任何设置(5155进程cat)

设置为前台service的进程(5156进程cat)

最后根据进程的oom_score来决定究竟斩谁的首,那么oom_score是怎么算出来的呢?他正是通过刚才讲的oom_adj、占用内存大小、启动时间等加权算出oom得分,得分最高者立斩。那么oom_adj的值又是谁在维护他呢,activity的生命周期是只有framework才知道,kernel不知道,所以这件事自然是由总管家ActivityManagerService来做


然而真正的lowmemorykiller却是在kernel层,源码位于Android 源码/kernel/drivers/staging/android/lowmemorykiller

以下是具体杀进程的代码片段



是的,信号。当然没这么简单!后面再说


那么第三方安全软件是怎么杀进程的呢?首先系统提供的方法就有


注释讲的明白,会在过会儿需要的时候再启起来,只需配置一个start_stick就杀不死,这个太low。

那么来看看framework自己是怎么管理的,杀掉前台进程以外的所有进程


向下跟代码


继续


与killProcessQuiet不同的是killProcess,发送的信号不同


通过反射,需要root权限

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


看到了吗?第一段注释,会杀掉所有和该packageName共享uid的进程,会取消掉该进程所有闹钟!百分之九十五的保活难逃此劫,但是marsdaemon可以做到,这里先卖个关子,以后慢慢讲,正在整理代码,上传github。


通过fc杀掉的进程在packagemanager中还会设置一个flag,以至于之后所有的广播都会将你过滤掉,防止你被系统的广播呼起,直到用户手动点击icon启动该应用,该flag才会置为false。当然这只针对系统广播,我们自己发的广播只要加入一个flag值就ok了。

force close 方法这么屌,第三方能不能用呢?我们根据这个方法要求的permission,在源码中找到该permission的定义


需要系统签名!所以第三方只能呵呵?但是!

但是!劳动人民的智慧是无穷尽的,最近好多第三方安全软件,推出了免root功能,除了利用短暂的系统漏洞侵入系统外,都是利用了android的AccessibilityHelper,这个功能初衷是帮助老年人或者视力有障碍的人群进行模拟点击操作,只要应用经过用户授权,就可以获取当前屏幕的所有控件以及空间上的信息,模拟手指触屏操作。于是乎,所谓的免root是让你给他们授权,然后他们给你在手机上点点点,点到settings中找到对应package点击force close,被用户看到你在操控他的手机当然不好,于是上面盖一个window当遮羞布,给你显示个进度条,后面不停点点点,就是这样。有空再发一下AccessibilityHelper 的demo。

此外有了root权限,可以直接用代码在terminal中调用kill -9 pid命令,等同于发送一个kill信号来杀死进程。

说了这么多,第三方的安全软件进程清理到底具体采用了哪种手段,以及使用了其他我不知道的方法。但是归根结底都是一个kill,所以我们只关心进程死掉的一瞬间。

0 0
原创粉丝点击