IM推送保障及网络优化详解(一):如何实现不影响用户体验的后台保活
对于移动APP来说,IM功能正变得越来越重要,它能够创建起人与人之间的连接。社交类产品中,用户与用户之间的沟通可以产生出更好的用户粘性。
在复杂的 Android 生态环境下,多种因素都会造成消息推送不能及时达到客户端。另外,不稳定的移动网络也给数据传输的速率和可靠性增加了障碍。
本文详解了网易云信IM SDK在应对弱网环境、移动端硬件限制以及Android复杂的生态现状时的探索与心得.如何实现不影响用户体验的后台保活,改善的长连接加推送组合方案,以及在弱网环境大数据传输的优化实践。
带着思考阅读:
1.什么是IM
2.IM SDK如何实现不影响用户体验的后台保活
3.如何做长连接加推送组合方案
4.如何在弱网环境下优化大数据传输
IM的定义
IM由两个字组成:Instant,Messaging。
即时性要求有新消息时能够立即收到,如果程序在后台,则要能立即收到推送通知。
通信则要求稳定可靠,系统不宕机,程序不崩溃,安全,传递消息时不会被拦截监听,消息不丢,顺序不乱,不重复,如果包含音视频聊天,则要求延迟低,流畅不卡顿。
要真正做出一套稳定可靠的商用级IM系统,挑战非常大。
第一个问题是消息推送。iOS有 APNS做推送,相当稳定。Android本身也有GCM可以用,但是在国内有“墙”,直接就把GCM等等google的服务全部挡在外面。为了实现即时稳定的消息推送,从易信时代开始,网易就开始研究,随着时间的推移,困难和方法也在不停的变化。
对于IM,当APP退到后台,是必须还能够收到新消息提醒的,没有GCM,怎么办?在最初,唯一能做的,就是后台运行了。这几乎是接收推送的唯一途径,就算是到现在,也是最主要的途径。Android从设计上,就是支持真后台运行的,后台运行的特性也是Android现在能如此成功的原因之一,但另一面,Android长久以来一直摆脱不了的卡顿,耗电等坏名声,后台运行也拖不了干系。因此,系统对于后台运行也不会放任自流。
APP在后台运行所面对的四大障碍
第一个障碍是Android的Low Memory Killer机制。手机的内存有限,当后台运行的进程越来越多,内存剩余量也就随之减少。当有一个新的APP想要启动,如果内存不够,LMK机制就会启动,从正在运行的进程中挑选一个清理掉,释放出空间,然后新的APP就可以运行了。
LMK有两个尺度去评判。一个是进程优先级,优先级越低,被清理的可能性越大,另一个是内存占用,占的内存越多,被清理的权重自然也越大。
因为LMK机制的存在,虽然APP允许在后台运行,但同样也面临随时被清理的风险。因此,网易需要在被清理后及时的重新启动。
第二个障碍是alarm,闹钟,有循环闹钟和一次性闹钟两种,在闹钟触发后启动对应的组件。
第三个障碍是在Manifest文件中静态注册的Receiver,通过监听各种系统事件,比如开机,网络变化,mount/unmounts等,在这些事件发生时启动组件,因为这种方式会造成在这些事件发生时系统容易卡顿,在7.0里面,Android增加了限制。
第四个障碍是JobScheduler,这是在5.0里面新增的,允许APP在特定事件发生时做一些动作,比如充电,切换到wifi等。
虽说无论怎么做,APP终究免不了一死,但通过对照LMK的评判准则,还是可以降低APP被清理的概率的。第一个就是降低进程的内存占用。如果采用单进程的模式,由于进程中包含了UI,Webview,各种图片缓存等内容,内存必然会居高不下,降不下来。IM软件一般都会采用双进程甚至多进程的策略,将push进程独立出来,在push进程里只处理网络连接和push业务,不参与任何其他业务逻辑,更不包含任何UI。
以下是网易云信Android SDK的架构,按照分层的结构模式设计。最底下青色的一层是push层,他就是作为一个独立进程运行的。他只负责处理网络长连接的相关工作,比如安全加密,心跳,鉴权,封包解包等工作,所有业务逻辑都交给UI进程的服务模块去做。来看一下云信demo的进程内存占用情况。上面一个是主进程,看第四列PSS的数据,内存占用是50M左右,下面一个是push进程,内存占用只有10M左右。当处于后台时,push进程被清理概率比UI主进程低很多。
(网易云信SDK架构)
降低被清理概率的第二个手段是提升进程优先级。先看这个例子,这是绿色守护的一个截图,最上面是“暂不自动休眠”,因为这里列出的两个APP的状态都是工作中,对应的进程优先级是“可视进程”。但这两个APP并没有提供桌面小部门在运行,也没有指示前台服务的常驻通知栏提醒,事实上,他们就只是在后台运而已。通常进程退到后台后,其进程优先级类型就变成了较低的后台进程,而不是这样的“可视进程”,他们是通过什么方法来提升优先级,降低被清理概率呢?
(绿色守护截图)
Android在设计前台服务上有一个漏洞,通过两个服务配合就能创建一个隐形的前台服务。这里有两个已经启动的service: A和B。先在A中调用startForeground,提供一个NOTIFY_ID, 然后A就变成前台服务了,同时有了一个ID为NOTIFY_ID的常驻通知栏提醒,然后网易在B中也调用startForeground,提供相同的NOTIFY_ID, B也变成了前台服务,因为两个通知ID相同,因此这一次就不会创建新的通知栏提醒了。然后再在A中调用stopForeground,A的前台属性被取消,同时,常驻通知栏提醒也会被移除,但是,service B并不会受到任何影响,还是前台服务,这是再把A停掉,进程就只剩下前台服务B了,进程也变成了前台进程,但用户不会有任何感知。
正常来说,做了上面3步之后,进程就能够比较稳定的在后台运行了。
但在有些情况下,推送进程却永远起不来。跟踪之后发现,除了系统能够杀掉后台运行的进程外,用户也一样是可以杀死进程的。用户杀掉进程的方式有两种,一种是在最近任务列表中将app划掉,这种方式和系统杀掉进程效果相同。另外一种就是通过这里的force stop,这种方式比系统清理更加彻底。不但app正在运行的进程会被清理,app当前在重启列表中的待重启服务,注册的各种闹钟,事件监听组件等都会被移除,除非用户在主动点击或者系统重启等外力,app没法再自己重新爬起来了。
在有些国内的像MIUI一类的ROM上,用户从最近任务列表中将app移除,效果竟然也是force stop。正常来说,如果是用户主动操作,app本身也不应该再重启了。但有些时候这个并不是用户本意,况且,对于IM软件来说,消息推送是一定要得到保障的,否则不明正确的吃瓜群众们会觉得是软件不行,连消息推送都做不好。
APP安卓进程保活的好办法
第一个是通过两次fork加上exec的方式。两个fork后,第一次fork的进程退出,第二次fork出来的进程就会被init进程领养。用户此时再force stop,因为这个进程复进程是init,而不是Zygote,因此不会被清理。由于这个进程还是从android进程fork出来的,带有android运行时环境以及复进程的资源,所以内存会比较大,这里可以再通过exec命令,打开一个纯linux的可执行文件,开启一个daemon进程,其内存占用大概只有100K+,对用户也就完全无感了。利用这个后台进程,可以定时的将push进程拉起来。此种方式只在5.0以下的系统中有效,在4.4及以上系统中,SELinux特性是强制开启的,exec没有权限执行,同时在5.0之后,ActivityManager在做force stop以及移除任务时,只要是具有相同的uid的进程,就会全部清理掉,不再漏掉没有虚拟机环境的进程。
最后一个后台保活的手段是一个大杀器。因为前面所列的所有保活手段都不是那么保险,因此想出来这么一个互相保活的方式。当一个APP进程起来后,他就去扫描已安装的应用列表,看看有没有自己的兄弟姐妹,比如说同一个长的APP,或者是集成了同一个SDK的APP,如果有,就把这些APP都拉起来。这也就是现在比较出名的“全家桶”方案。虽说这种方法确实能够带来较高的后台存活率,特别是那些大厂和应用广泛的sdk,但是这种方式对于用户的伤害也非常大,如果有后台推送的必要性,且不会对用户体验造成太大伤害时,此方式还可以使用,但如果只是为了推广告,则会对用户造成伤害,反过来,也可能会导致用户直接卸载APP。
现在各种手机管理软件都会对这种全家桶唤醒方式做限制,特别是在root过的机器上,可以做到完全切断这些唤醒路径。同时,很多ROM也会自带管理软件,限制后台运行和后台唤醒,以便给设备换取更长的续航。在目前国内的Android生态环境中,无论采用什么方式,想要一直在后台运行时越来越难了,需要重新想另外的办法来保障消息推送。另一方面,作为开发者,也有义务为用户提供更好体验的软件,而不是无休止的在后台浪费用户的资源。
IM推送保障及网络优化详解(一):如何实现不影响用户体验的后台保活的更多相关文章
- IM推送保障及网络优化详解(二):如何做长连接加推送组合方案
对于移动APP来说,IM功能正变得越来越重要,它能够创建起人与人之间的连接.社交类产品中,用户与用户之间的沟通可以产生出更好的用户粘性. 在复杂的 Android 生态环境下,多种因素都会造成消息推送 ...
- Git学习系列之Git基本操作推送项目(图文详解)
前面博客 Git学习系列之Git基本操作提交项目(图文详解) 如果完成到一定程度,那么可以推送到远端在线仓库. 推送之前,请确保你已经设置了全局的 user.name 和 user.email, 如果 ...
- 个推安卓推送SDK集成步骤详解
以下是一位开发者在集成个推安卓推送SDK时候的亲身经历: 作者:吃饱了想睡. 概述 公司准备采用个推作为第三方推送平台,我作为客户端的头号小鸟,掐指一算已经毕业 0.1 年了,Leader 准备把这个 ...
- Android群英传笔记——第十二章:Android5.X 新特性详解,Material Design UI的新体验
Android群英传笔记--第十二章:Android5.X 新特性详解,Material Design UI的新体验 第十一章为什么不写,因为我很早之前就已经写过了,有需要的可以去看 Android高 ...
- 个推推送iOS版 常见问题详解
原文:http://www.oschina.net/question/1782938_234760 1.提交了.p12文件后多久可以测试? 提交后10分钟左右才可以测试,并不是立即生效的. 2 ...
- 【TCP/IP详解 卷一:协议】第二十三章 TCP的保活定时器
本章介绍保活定时器. 在 TCP 的三握四挥 章节中,我们介绍了 处在 TIME_WAIT 的 2MSL定时器:在 TCP的超时与重传 章节中,我们介绍了 重传定时器:在上一章节中,我们介绍了 防止死 ...
- 详解nginx、php-fpm和mysql用户权限
通常情况下,我们运行web应用的服务器有CentOS.Ubuntu.Debian等等的Linux发行版本.这时候,构成服务架构所必须的Nginx.php和MySQL等应用的权限控制就显得非常重要,各个 ...
- Server push(服务器推送技术)
一.服务器推送技术Server Push详解: 推送技术Server Push的基础思想是将浏览器主动查询信息改为服务器主动发送信息.服务器发送一批数据,浏览器显示这些数据,同时保证与服 ...
- Git学习系列之Git基本操作拉取项目(图文详解)
前面博客 Git学习系列之Git基本操作推送项目(图文详解) 当然,如果多人协作,或者多个客户端进行修改,那么我们还要拉取(Pull ... )别人推送到在线仓库的内容下来. 大神们是不推荐使用 pu ...
随机推荐
- python 反转列表
翻转一个链表 您在真实的面试中是否遇到过这个题? Yes 样例 给出一个链表1->2->3->null,这个翻转后的链表为3->2->1->null 步骤是这样的: ...
- 4.生产者 消费者模式的RabbitMQ
1.生产者: using RabbitMQ.Client; using System; using System.Text; namespace Publisher1 { class Program ...
- 在.net MVC项目的区域中使用模板页
1.首先 在网站的区域目录areas下 的 区域目录下的 Views目录下新建一个 _ViewStart.cshtml文件 如下图所示: 2.在shared文件下新建一个视图作为Layout ...
- BLAS 与 Intel MKL 数学库
0. BLAS BLAS(Basic Linear Algebra Subprograms)描述和定义线性代数运算的规范(specification),而不是一种具体实现,对其的实现包括: AMD C ...
- CMMI能力成熟度模型集成的过程域
什么是CMMI CMMI全称是Capability Maturity Model Integration, 即能力成熟度模型集成,是由美国国防部(Office of the Secretary of ...
- WPF 用Clip属性实现蒙板特效
原文:WPF 用Clip属性实现蒙板特效 上一篇,已简单介绍Clip属性的用法,这一篇用它来实现简单蒙板功能,很简单,直接上代码 <Window x:Class="擦除效果.MainW ...
- Plugin execution not covered by lifecycle configuration
Eclipse 环境 在工作空间 \.metadata\.plugins\org.eclipse.m2e.core\ 目录下 增加 lifecycle-mapping-metadata.xml 文件 ...
- WPF - 模板查看工具:Show Me The Template及如何查看第三方主题
原文:WPF - 模板查看工具:Show Me The Template及如何查看第三方主题 在学习WPF的模板(DataTemplate.ItemsPanelTemplate.ControlTemp ...
- WCF的几个注意事项
wcf托管服务注意的问题 加上项目分为客户端-WCF服务-逻辑层-数据库三层wcf一直出现异常,说没有初始化啊之类的,如果你的逻辑代码确定没有问题的话,思考是不是wcf的配置文件(app.config ...
- JDK源码阅读——LinkedList实现
1 继承结构图 LinkedList是List的另一种实现.继承自AbstractSequentialList 2 数据结构 LinkedList与ArrayList不同的是LinkedList底层使 ...