简介

众所周知,Android渠道的办理机制下,App进入后台后,为了供给继续的及时服务(如推送、音乐),或进行驻留获取收益(盯梢、信息收集、广告)等,会使用一些办法来让自身坚持活泼,躲过被Android体系或用户发觉、整理,完成后台驻留。

其间,后台驻留的广义概念,除了坚持在后台运转外,被其他组件拉起也归于驻留(唤醒)。

因为驻留会对体系的功用、呼应延迟、续航、发热等带来负面影响,令体系的资源办理作用下降,归于违背用户志愿和知情的恶劣行为,因而将这些App称为固执(Diehard)使用,其使用的办法称为固执办法。

除了App使用的一些黑科技(乃至是在违法边际的擦边手法)以外,Android体系自身自带的机制也能够完成保活和拉起。这些保活、拉起机制,大略划分为两类:

  1. 坚持活泼,在后台运转不被整理、收回
  2. 被其他组件唤醒,包括被其他App唤醒、被体系供给的功用唤醒

本文总结上述这两类会被固执App使用的机制。

进程和Task办理

首先简单整理一下Android Framework层基本的进程办理。

Android渠道依据Linux,除了依据Linux的“进程”维度来进行办理外,还依照Task的概念来办理使用进程,分别为ProcessRecord和TaskRecord。体系能够按Task也能够按Process来办理进程。

Android供给接口直接杀死Linux进程:1. ProcessRecord的kill()办法,其完成是向对应的进程发送SIGNAL_KILL信号;2. libc的kill()函数,也是发送信号

OOM停止进程(LMK)

App进程在体系中依据OOM(Out of Memory)ADJ(Adjustment)等级和进程状况来确定优先级,当体系需求杀死进程来释放内存时,优先级越低的会优先停止。OOM ADJ分数越小优先级越高。

因为固执App进程后台驻留时或许会被体系收回,因而固执App一般经过一些手法(services、弹窗)等来下降OOM(进步优先级),减少自身被体系收回的几率。

最近使命列表完毕Task

用户在多使命界面(Recents)移除使用,体系会完毕使用对应的Task:Removing Recent Task Item(RRT)。

该操作会完毕掉与Task相关的进程,但在一些场景下仍然会有对应App的进程没有被杀死。

  1. 当App经过”Exclude from recents”功用(不在最近使命列表显现自己)时,没有供给给用户完毕的机会,就没有手动完毕掉Task的进口
  2. 当一个进程归于多个Task时(该进程还需求为其他Task服务)

这类停止机制由用户操作触发,当固执使用凭借多进程、多使命、唤醒拉起、互拉等操作,被停止后仍在后台运转(或后续又被唤醒),给用户感受为“杀不洁净”。

强制完毕App

强制完毕(Force-Stop)时Android内建的功用,由ActivityManagerService供给接口,能够在设置-使用程序界面由用户手动调用。

强制完毕的领域是App对应的一切Task(即能够杀死一般App一切进程)。FSA还额定会将App设置为“STOPPED“状况,制止使用在下一次被用户手动启用或使用跳转前被播送、服务等唤醒。强制完毕对固执App的作用不佳,许多固执App具备Native保活能力、互拉保活、唤醒拉起等对立措施。

此外,Android供给KILL_BACKGROUND_PROCESSES权限,答应具备权限的App调用API杀死ADJ大于SERVICE_ADJ的后台进程(即没有Service的后台进程能够被杀掉)。

坚持活泼或唤醒

从最近使命躲藏或多个最近使命

Android渠道供给的excludeFromRecents功用能够让App的Task在多使命中躲藏。此外一个进程能够归于不同的Task,发生多个Task并躲藏其间几个Task能够完成”杀不洁净“的作用。

进步App进程优先级、阻挠部分收回场景

LMK和OOM ADJ会受到进程状况和优先级的影响,进步优先级能够下降被体系收回的几率,阻挠部分会杀进程的场景。

其间,将凭借前台进程绑定后台服务进程保活的手法,是较常见的“杀不死、杀不洁净”的状况(最近使命移除后仍有进程)。

  1. 接收播送,启动Receiver,具有Receiver的后台进程优先级高于无Receiver的后台进程
  2. 创建前台Service(高版别Android前台service需求带有告诉),OOM ADJ更低(SERVICE_ADJ),杀死概率更低,此时进程不会被“杀死后台进程”杀掉(会越过ADJ小于等于SERVICE_ADJ的进程)
  3. 坚持前台Activity,OOM ADJ更低(用户可见的Task)
  4. 创建前台窗口(悬浮窗)或掩盖窗口(将窗口盖在前台App上面)
  5. 将后台服务绑定到前台进程,赋予后台服务在的进程更低的OOM,进步该进程的优先级,减少被杀的几率;同时对应进程不再归于后台进程,不会被“杀死后台进程”杀死,且该进程转为“需求为其他Task服务”,相同不会被最近使命移除时杀死
  6. 关于涉及Service的场景,ContentProvider也适用

凭借Sticky Service唤醒

黏性Service是体系供给的机制,被杀死后会由体系调度进行重启。前述的force-stop杀死的进程,因为设置的“STOPPED”状况是会被越过的,因而这种状况杀死的进程不会再自动重启。大多数ROM对此都有限制(次数、频率)。

凭借播送唤醒

经过体系或其他App、组件宣布的播送能够唤醒使用,固执使用能够凭借播送来完成唤醒自启。相同的,force-stop设置的“STOPPED”状况也会让播送越过这些App,不会唤醒这些App来传递播送。但播送带有一个特例功用,带有FLAG_INCLUDE_STOPPED_PACKAGES的播送能够无视“STOPPED状况”,仍会唤醒force-stop的App。一般体系播送没有这个FLAG,基本上是其他使用宣布的播送带有。

高版别的Android现已不再触发静态播送和隐式播送,这种唤醒方式少了很多。(但有FLAG_RECEIVER_INCLUDE_BACKGROUND和FLAG_INCLUDE_STOPPED_PACKAGES躲避)

凭借Alarm Service守时器唤醒

Alarm是Android供给的守时器功用,守时器timeout时会唤醒App。被force-stop的使用会自动移除掉注册的守时器,因而不会被唤醒。

凭借Job Scheduling Service使命调度唤醒

与Alarm相似,守时唤醒App。但是受到电源办理战略、功耗办理战略、体系休眠状况、WorkManager等的影响,唤醒的守时精度较低,且不同ROM或许表现一致性较差。相同的,会越过被force-stop的App。

凭借其他App拉起唤醒

这是国内互联网App最恶心的一种机制,一群App(或集成的SDK)相互拉起对方、相互绑定进步优先级、相互拉起唤醒。其间,唤醒方式除了惯例的四大组件外,还有一些黑科技、Native的办法。其间,App宣布的播送带上FLAG_RECEIVER_INCLUDE_BACKGROUND和FLAG_INCLUDE_STOPPED_PACKAGES完全能够躲避force-stop后”STOPPED”的使用,完成唤醒。

总结

能够说,Android自身的办理机、供给的组件间通讯功用,叠加App们的流氓行为,能够说后台驻留、拉起唤醒是防不胜防的,完成较好的后台驻留办理需求较高的投入,且对体系稳定性、App基本功用的影响较大,是高投入高难度的研讨方向。其间,App互拉唤醒和保活的机制,让force-stop机制做不到太好的作用,其”STOPPED”完成的相似的轻度冻住状况简直作废,也是各大ROM厂商在后台办理部分大展身手的重要因素。

为了完成好的功耗、续航、功用,就需求在使用唤醒、冻住、暂停执行等方面下功夫了。