Android 服务为啥保不活

转发请注明出处:https://www.jianshu.com/p/bf0c82be9b25
请尊重原创作者


有一段时间都在说服务怎么保活,怎么才能不被杀死,各种花里胡哨的保活方案抄来抄去,到头来 能打的 一个都没有。

硬核场景
既然这么多可操作性低的“保命方案”,那么需要知道些什么知识点才能脱颖而出,好吧我们提供不了保活的黑科技,如果对方按套路出牌的话,至少会让你解释下为什么保不活。

GC
就是因为GC机制,所以我们的服务才保不活,但是这个过程我们不可控,很难让运行中的应用感知什么时候GC触发了,从而做点什么来补救。所以才有了 轮询机制 来唤醒,一段时间检查下服务有没有在跑,没有就再扶起来继续送。

通常情况下,触发GC的条件有两个:
1.当应用程序空闲时,即没有应用线程在运行时,GC会被调用(随心随意收垃圾)
2.Java堆内存不足时,GC会被调用(被强制叫去收垃圾)

D/dalvikvm: GC_CONCURRENT freed 2012K, 63% free 3213K/9291K, external 4501K/5161K, paused 2ms+2ms

各参数对照含义
D/dalvikvm: <GC_Reason> <Amount_freed>, <Heap_stats>, <External_memory_stats>, <Pause_time>

相信大家都很熟悉这log,但对它表达的意义估计就看不太懂,为了方便解释,把各参数对照在上面列出,简单说个参数,其它大家再去详细了解GC的参数解读吧。

GC Reason 就是指引起GC原因,有以下几种:

  • GC_CONCURRENT:当堆开始填充时,并发GC可以释放内存。
  • GC_FOR_MALLOC:当堆内存已满时,app尝试分配内存而引起的GC,系统必须停止app并回收内存。
  • GC_HPROF_DUMP_HEAP:当你请求创建 HPROF 文件来分析堆内存时出现- 的GC。
  • GC_EXPLICIT:显示的GC,例如调用System.gc()(应该避免调用显示的GC,信任GC会在需要时运行)。
  • GC_EXTERNAL_ALLOC:仅适用于 API 级别小于等于10 ,用于外部分配内存的GC。

回到正题,GC为什么导致服务保不活?那是因为在当各种情况下触发了垃圾回收,它就会去找能宰的都宰掉,从而挤出内存给那些优先给用户接触到的应用或服务。所以才会有 Notification的前台服务 这样的做法让服务不轻易被杀死,尽可能把服务提升靠近用户,但是其核心思想都是为了改变 oom_adj 的等级,等级越低越重要越不容易被杀死。在解释改变等级之前,有个等级的概念需要先了解的。

进程等级
还是大家熟知的知识点,进程等级可以划分为这五大类:
1.前台进程
2.可见进程
3.服务进程
4.后台进程
5.空进程

他们在不同场景下,会对应到某一个值,具体查看方法可以用 adb 的命令查看。但这还只是等级概念,能大概地估算被杀死的可能性。而最终决定会不会被杀的是一个叫做 阀值 概念的值,这就涉及到 linux 的知识点,我们只需要知道 linux 会通过某个计算方式得出一个叫做 oom_score 的值,而这个就是和GC有直接关系了,因为根据不同情况,GC回收的程度不一样,那么每个等级都有对应阀值,只要没超过这个阀值的进程,就不会被回收。

比如说,这次GC只宰到 “后台进程” 的最低阀值,那么 “空进程”、“后台进程” 都会被宰,而 [服务进程]、[可见进程]、[前台进程] 这些进程安然无事,但某一时机这个阀值被系统调得更严格,需要更多内存了,调到 “服务进程” 的最低阀值,那么按照这个道理, “空进程”、“后台进程” 、“服务进程” 都会被宰掉。好,那么我们平时怎么知道自己的服务在什么等级呢?

oom_adj

adj级别 解释
UNKNOWN_ADJ 16 预留的最低级别,一般对于缓存的进程才有可能设置成这个级别
CACHED_APP_MAX_ADJ 15 缓存进程,空进程,在内存不足的情况下就会优先被kill
CACHED_APP_MIN_ADJ 9 缓存进程,也就是空进程
SERVICE_B_ADJ 8 不活跃的进程
PREVIOUS_APP_ADJ 7 切换进程
HOME_APP_ADJ 6 与Home交互的进程
SERVICE_ADJ 5 有Service的进程
HEAVY_WEIGHT_APP_ADJ 4 高权重进程
BACKUP_APP_ADJ 3 正在备份的进程
PERCEPTIBLE_APP_ADJ 2 可感知的进程,比如那种播放音乐
VISIBLE_APP_ADJ 1 可见进程
FOREGROUND_APP_ADJ 0 前台进程
PERSISTENT_SERVICE_ADJ -11 重要进程
PERSISTENT_PROC_ADJ -12 核心进程
SYSTEM_ADJ -16 系统进程
NATIVE_ADJ -17 系统起的Native进程

在终端输入命令(过程就大概是 先连接设备;进入shell;获得进程pid;查看值)
adb shell
cat /proc/{pid}/oom_adj


查看oom_adj的终端命令

如图所示了,某一个进程等级在 -13 那么对照到上面的表,可以知道起码是 系统进程 级别,那么普通的GC基本是宰不到它的。所以保活的核心,就是为了提升这个等级,类似的思想就有在AndroidManifest.xml的服务增加 优先级priority ,就尽量在这个阀值的范围往上靠,希望别宰到我。

不过
也不是没有办法保活,你需要知道一下这几个属性的作用,但有个前提咯!要提升到系统级别,唯一有效而且安全的做法,就是有 系统签名 。类似的,每个品牌每个主板每个型号都有会它的签名文件,就如平时我们自己生成的那种 jks、keystore 文件(只不过它们由 platform.x509.pem、platform.pk8 这些来生成),然后下面这些属性就能起作用

android:sharedUserId="android.uid.system"
这个属性使用应该会比较少,官方对它的解释:与其他应用程序共享的Linux用户ID的名称。默认情况下,Android为每个应用程序分配了自己唯一的用户ID。但是,如果将该属性设置为两个或多个应用程序相同的值,它们将共享相同的ID——前提是它们的证书集相同。具有相同用户ID的应用程序可以访问彼此的数据,如果需要,还可以在相同的进程中运行。

换言之,你得有系统签名才能和他们平起平坐。

persistent=true
这个在保活文章出现的频率就比较高了,但是却不怎么起作用,再来看看官方解释:应用程序是否应该一直运行—如果应该,则为“true”;如果不应该,则为“false”。默认值为“false”。应用程序通常不应设置此标志;持久性模式仅适用于某些系统应用程序。

通常情况下,我们的包都会安装到 data/data/ 目录下,而 persistent 需要 system/app 配套使用才会起效果的,也就是说应用本身就已经是系统应用,那么这个属性才生效,才会在系统启动的时候拉起有该属性的应用,并且被杀死后能够重启应用。

那我们怎么验证自己的属性有没有生效呢?
adb shell dumpsys meminfo


专业素养,打码了

看一下自己的应用包名有没有出现在 Persistent 列表就行了,按照网上那些保活方式,通常只会出现在 A Services 、Visible、Foreground 这些列表内。

总结
大家对服务为啥保不活,有了个整体概念,那么概括成一句话应该就是:GC可能会杀死等级 oom_adj 不太重要的服务,而我们所做的一切都是为了提升这个等级的值,让它不那么轻易被杀死。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335