在发生特定系统事件时,系统会发出响应的广播,通过在 AndroidManifest 中“静态”注册对应的广播监听器,即可在发生响应事件时拉活。
常用的用于拉活的广播事件包括:
4.1.2. 方案适用范围
适用于全部 Android 平台。但存在如下几个缺点:
1) 广播接收器被管理软件、系统软件通过“自启管理”等功能禁用的场景无法接收到广播,从而无法自启。
2) 系统广播事件不可控,只能保证发生事件时拉活进程,但无法保证进程挂掉后立即拉活。
因此,该方案主要作为备用手段。
4.2. 利用第三方应用广播拉活
4.2.1. 方案设计思想
该方案总的设计思想与接收系统广播类似,不同的是该方案为接收第三方 Top 应用广播。
通过反编译第三方 Top 应用,如:手机QQ、微信、支付宝、UC浏览器等,以及友盟、信鸽、个推等 SDK,找出它们外发的广播,在应用中进行监听,这样当这些应用发出广播时,就会将我们的应用拉活。
4.2.2. 方案适用范围
该方案的有效程度除与系统广播一样的因素外,主要受如下因素限制:
1) 反编译分析过的第三方应用的多少
2) 第三方应用的广播属于应用私有,当前版本中有效的广播,在后续版本随时就可能被移除或被改为不外发。
这些因素都影响了拉活的效果。
4.3. 利用系统Service机制拉活
4.3.1. 方案设计思想
将 Service 设置为 START_STICKY,利用系统机制在 Service 挂掉后自动拉活:
4.3.2. 方案适用范围
如下两种情况无法拉活:
-
Service 第一次被异常杀死后会在5秒内重启,第二次被杀死会在10秒内重启,第三次会在20秒内重启,一旦在短时间内 Service 被杀死达到5次,则系统不再拉起。
-
进程被取得 Root 权限的管理工具或系统工具通过 forestop 停止掉,无法重启。
4.4. 利用Native进程拉活
4.4.1. 方案设计思想
主要思想:利用 Linux 中的 fork 机制创建 Native 进程,在 Native 进程中监控主进程的存活,当主进程挂掉后,在 Native 进程中立即对主进程进行拉活。
主要原理:在 Android 中所有进程和系统组件的生命周期受 ActivityManagerService 的统一管理。而且,通过 Linux 的 fork 机制创建的进程为纯 Linux 进程,其生命周期不受 Android 的管理。
4.4.2. 方案实现挑战
挑战一:在 Native 进程中如何感知主进程死亡。
要在 Native 进程中感知主进程是否存活有两种实现方式:
-
在 Native 进程中通过死循环或定时器,轮训判断主进程是否存活,档主进程不存活时进行拉活。该方案的很大缺点是不停的轮询执行判断逻辑,非常耗电。
-
在主进程中创建一个监控文件,并且在主进程中持有文件锁。在拉活进程启动后申请文件锁将会被堵塞,一旦可以成功获取到锁,说明主进程挂掉,即可进行拉活。由于 Android 中的应用都运行于虚拟机之上,Java 层的文件锁与 Linux 层的文件锁是不同的,要实现该功能需要封装 Linux 层的文件锁供上层调用。
封装 Linux 文件锁的代码如下:
Native 层中堵塞申请文件锁的部分代码:
挑战二:在 Native 进程中如何拉活主进程。
通过 Native 进程拉活主进程的部分代码如下,即通过 am 命令进行拉活。通过指定“—include-stopped-packages”参数来拉活主进程处于 forestop 状态的情况。
挑战三:如何保证 Native 进程的唯一。
从可扩展性和进程唯一等多方面考虑,将 Native 进程设计层 C/S 结构模式,主进程与 Native 进程通过 Localsocket 进行通信。在Native进程中利用 Localsocket 保证 Native 进程的唯一性,不至于出现创建多个 Native 进程以及 Native 进程变成僵尸进程等问题。
4.4.3. 方案适用范围
该方案主要适用于 Android5.0 以下版本手机。
该方案不受 forcestop 影响,被强制停止的应用依然可以被拉活,在 Android5.0 以下版本拉活效果非常好。
对于 Android5.0 以上手机,系统虽然会将native进程内的所有进程都杀死,这里其实就是系统“依次”杀死进程时间与拉活逻辑执行时间赛跑的问题,如果可以跑的比系统逻辑快,依然可以有效拉起。记得网上有人做过实验,该结论是成立的,在某些 Android 5.0 以上机型有效。
4.5. 利用 JobScheduler 机制拉活
4.5.1. 方案设计思想
Android5.0 以后系统对 Native 进程等加强了管理,Native 拉活方式失效。系统在 Android5.0 以上版本提供了 JobScheduler 接口,系统会定时调用该进程以使应用进行一些逻辑操作。
在本项目中,我对 JobScheduler 进行了进一步封装,兼容 Android5.0 以下版本。封装后 JobScheduler 接口的使用如下:
4.5.2. 方案适用范围
该方案主要适用于 Android5.0 以上版本手机。
该方案在 Android5.0 以上版本中不受 forcestop 影响,被强制停止的应用依然可以被拉活,在 Android5.0 以上版本拉活效果非常好。
仅在小米手机可能会出现有时无法拉活的问题。
4.6. 利用账号同步机制拉活
4.6.1. 方案设计思想
Android 系统的账号同步机制会定期同步账号进行,该方案目的在于利用同步机制进行进程的拉活。添加账号和设置同步周期的代码如下:
该方案需要在 AndroidManifest 中定义账号授权与同步服务。
4.6.2. 方案适用范围
该方案适用于所有的 Android 版本,包括被 forestop 掉的进程也可以进行拉活。
最新 Android 版本(Android N)中系统好像对账户同步这里做了变动,该方法不再有效。
5. 其他有效拉活方案
经研究发现还有其他一些系统拉活措施可以使用,但在使用时需要用户授权,用户感知比较强烈。
这些方案包括:
-
利用系统通知管理权限进行拉活
-
利用辅助功能拉活,将应用加入厂商或管理软件白名单。
这些方案需要结合具体产品特性来搞。
上面所有解释这些方案都是考虑的无 Root 的情况。
其他还有一些技术之外的措施,比如说应用内 Push 通道的选择:
-
国外版应用:接入 Google 的 GCM。
-
国内版应用:根据终端不同,在小米手机(包括 MIUI)接入小米推送、华为手机接入华为推送;其他手机可以考虑接入腾讯信鸽或极光推送与小米推送做 A/B Test。
更多精彩内容欢迎关注bugly的微信公众账号:
腾讯 Bugly是一款专为移动开发者打造的质量监控工具,帮助开发者快速,便捷的定位线上应用崩溃的情况以及解决方案。智能合并功能帮助开发同学把每天上报的数千条 Crash 根据根因合并分类,每日日报会列出影响用户数最多的崩溃,精准定位功能帮助开发同学定位到出问题的代码行,实时上报可以在发布后快速的了解应用的质量情况,适配最新的 iOS, Android 官方操作系统,鹅厂的工程师都在使用,快来加入我们吧!
?