ANR实战案例 - FCM拉活启动优化
系列文章目录
提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 Python 机器学习入门之pandas的使用
文章目录
- 系列文章目录
- 前言
- 一、Trace日志分析
- 二、业务分析
- 1.Firebase源码分析
- 2.Firebase官方查看
- 官方文档
- Demo中issue查看
- 三、问题分析
- 3.1 打点数据统计分析
- 3.2 冷启动时间测试
- 3.3 应用启动分析
- 3.4 启动优化
- 3.5 三方SDK初始化禁用效果
- 3.6 ANR优化效果
- 3.7 问题根治
- 3.8 问题复盘
- 总结
前言
一、Trace日志分析
如果您想降低 ANR 率,首先要做的是找出错误的原因。最直接的方法是尝试分析 Google Play 中排名靠前的 ANR 组。当我们检查控制台时,显示如下:

占比靠前的几乎每个组都有一个标题“ Broadcast of Intent { act=com.google.android.c2dm.intent.RECEIVE } … ”,包含该类型的ANR占比接近60%。Google Play 后台堆栈详情如下:

主线程堆栈:

从堆栈未找到该问题分析入口,于是在项目中搜索“ Broadcast of Intent { act=com.google.android.c2dm.intent.RECEIVE } … ”,得知该acttion为Firebase组件FCM发送通知拉活我们应用的广播。于是继续研究FCM内部实现。
二、业务分析
1.Firebase源码分析
搜索FirebaseSDK,发现“ Broadcast of Intent { act=com.google.android.c2dm.intent.RECEIVE } … ”是内部的一个静态注册广播,如下图所示:

该意图属于FirebaseInstanceIdReceiver广播,考虑是否广播这里出现了耗时?

查看其父类CloudMessagingReceiver中onMessageReceive调用方式:

可以看到onReceive方法内部虽然进行了混淆,但可以看到大概逻辑,是通过一个线程池中子线程进行处理返回的广播结果。好像处理的也没有毛病。
源码的这个方向没发现问题,继而换个思路查看官方文档及Demo。
2.Firebase官方查看
官方文档
通过源码查看,发现CloudMessagingReceiver属于messaging库。
官方文档地址:
https://firebase.google.com/support/release-notes/android#messaging_v23-0-7

messaging库升级为23.0.7后,Google play后台标题为“ Broadcast of Intent { act=com.google.android.c2dm.intent.RECEIVE } … ”类型的ANR比例没有明显下降。
然后查看Cloud Messaging更新记录,包括23.1.1等一共有5个版本致力于解决ANR,依次升级测试后仍然没有解决我们的问题。
Demo中issue查看
从官方提供Demo的issue查看,不少开发者也遇到了这个ANR:
然后做了如下尝试:
https://github.com/firebase/firebase-android-sdk/issues/3990

参考issue-3990中描述的方法,将广告初始化移到Activity阶段,似乎依然没有缓解问题。
https://github.com/firebase/firebase-android-sdk/issues/3468

参考issues-3468将基础库降级,以及新的Bom方式配套引入,均没有解决问题。
三、问题分析
基于前面的途径都没有解决问题,于是我决定自己根据该问题现象进行深入研究。
3.1 打点数据统计分析
首先,我对Firebase后台发生ANR时间点的打点数据进行了统计分析,发现大部分集中在Application.onCreate 阶段。
这让我好像看到了一点曙光,于是向 Application.onCreate 添加人为延迟并检查不同的场景。发现如下:
- 当用户使用launcher app手动触发app launch时,Application.onCreate中的主线程阻塞,即使阻塞几分钟也不会报ANR
- 当使用广播接收器启动应用程序时,主线程阻塞时间少于 10 秒时不会报告 ANR。
3.2 冷启动时间测试
于是让测试帮忙找了线上ANR发生率比较高的具有代表性的机型,进行了冷启动时间测试,发现很多中低端机型的冷启动时间超过10s。
ps:由于业务主要是非洲国家,线上包含了大量的低端机及平均使用5-7年的手机。
于是我开始思考,是否启动时间跟该ANR具有相关性?
3.3 应用启动分析
最终利用kotlin的init特性获取了冷启动阶段的.trace文件
class App: MusicApplication() {init {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {Debug.startMethodTracingSampling("startup", 8 * 1024 * 1024, 100)}}override fun onCreate() {super.onCreate()Debug.stopMethodTracing()}
}
trace概览如下:

详细:

由函数调用耗时发现,启动阶段的大部分耗时都是因为三方库使用contentProviders调用初始化代码,在Provider阶段产生的耗时。
查看系统源码可知,

先执行完installContentProviders方法,才会执行到callApplicationOnCreate。于是接下来就想办法处理三方库的自动初始化。
3.4 启动优化
对相关三方SDK使用的Provider初始化进行禁用,使用tools:node=“remove”,示例如下:
<!--禁用FirebaseApp初始化--><providerandroid:name="com.google.firebase.provider.FirebaseInitProvider"android:authorities="${applicationId}.firebaseinitprovider"android:exported="false"tools:node="remove"/><!--FirebasePerformance初始化禁用 --><providerandroid:authorities="${applicationId}.firebaseperfprovider"android:exported="false"android:initOrder="101"android:name="com.google.firebase.perf.provider.FirebasePerfProvider"tools:node="remove"/><!--阻止令牌自动生成,防止Firebase Analytics及messaging自动初始化,二者需同时禁用--><meta-dataandroid:name="firebase_messaging_auto_init_enabled"android:value="false" /><meta-dataandroid:name="firebase_analytics_collection_enabled"android:value="false" /><!--Google MobileAds广告SDK自动初始化禁用--><providerandroid:name="com.google.android.gms.ads.MobileAdsInitProvider"android:authorities="${applicationId}.mobileadsinitprovider"android:exported="false"android:initOrder="100"tools:node="remove"/><!--FaceBook 禁用 SDK 自动初始化功能--><meta-data android:name="com.facebook.sdk.AutoInitEnabled"android:value="false"/><providerandroid:name="com.facebook.internal.FacebookInitProvider"android:authorities="${applicationId}.FacebookInitProvider"android:exported="false"tools:node="remove"/>
禁用后在启动阶段异步进行手动调用。
由于使用到的三方SDK较多,上面只列举了部分SDK,还有其它:
- 融云SDK的Provider初始化禁用,通过反射调用。
- AutoSize库的Provider初始化禁用,通过AutoSize.checkAndInit调用。
- 其它
3.5 三方SDK初始化禁用效果
三方SDK使用的Provider初始化禁用后,优化效果如下:

图1-三方SDK自动初始化优化前,k7机型测试,应用进程创建耗时4.04s 
图2-三方SDK自动初始化优化后,k7机型测试,应用进程创建耗时0.12s
3.6 ANR优化效果
优化前Google play后台,“ Broadcast of Intent { act=com.google.android.c2dm.intent.RECEIVE } … ”类型ANR占比:

优化后Google play后台,“ Broadcast of Intent { act=com.google.android.c2dm.intent.RECEIVE } … ”类型ANR占比:

遗留的17.3%后面通过把FCM放到独立进程进行解决。
3.7 问题根治
FCM独立进程可参考:
<!--FCM独立进程 start-->
<serviceandroid:name="com.google.firebase.messaging.FirebaseMessagingService"android:directBootAware="true"android:exported="false"android:process=":light"tools:node="replace"><intent-filter android:priority="-500"><action android:name="com.google.firebase.MESSAGING_EVENT" /></intent-filter>
</service><receiverandroid:name="com.google.firebase.iid.FirebaseInstanceIdReceiver"android:exported="true"android:permission="com.google.android.c2dm.permission.SEND"android:process=":light"tools:node="replace"><intent-filter><action android:name="com.google.android.c2dm.intent.RECEIVE" /></intent-filter>
</receiver>
<!--FCM独立进程 end-->
继承FirebaseInstanceIdReceiver的自定义类也得改为独立进程,否则收不到FCM推送消息。
然后通过跨进程广播传递FCM通知。
3.8 问题复盘
回顾第二小节的Firebase源码分析,已知Firebase的Messaging库内部是通过广播的形式来发送消息,实现业务App的拉活,查看常见ANR超时场景,前台广播的超时时间为10s,所以问题的根源还是应用被拉起的启动时间过久,导致该广播超时,从而产生了ANR。

总结
一般做海外业务的同学才会用到Firebase库,但解决问题的思路类似。当碰到此类疑难ANR问题,trace.txt获取不到与应该相关堆栈时,可参考本篇思路进行分析。
相关文章:
ANR实战案例 - FCM拉活启动优化
系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 例如:第一章 Python 机器学习入门之pandas的使用 文章目录 系列文章目录前言一、Trace日志分析二、业务分析1.Firebase源码分析2.Firebase官方查看官方文档Dem…...
Kali-linux查看打开的端口
对一个大范围的网络或活跃的主机进行渗透测试,必须要了解这些主机上所打开的端口号。在Kali Linux中默认提供了Nmap和Zenmap两个扫描端口工具。为了访问目标系统中打开的TCP和UDP端口,本节将介绍Nmap和Zenmap工具的使用。 4.4.1 TCP端口扫描工具Nmap 使…...
判断浏览器是否支持webp图片
.WebP是谷歌主导的开放免费的网络图像格式,其核心编码来自VP8也就是同时支持WebP图片和WebM视频等。 这种图像格式追求的并不是无损画质,而是在有损画质的情况下尽可能的压缩图像体积但也尽量降低清晰度下降。 谷歌资助和发展该图像格式最主要的目的就是…...
【Qt编程之Widgets模块】-007:QTextStream类及QDataStream类
1 概述 QTextStream和QDataStream都是对流进行操作 QTextStream只能普通类型的流操作像QChar、QString、int…,其实就很类似我们c或者c中读写文件的感觉, QDataStream就厉害了,无论是QTextStream的普通类型的流操作还是一些特殊类型的流操作…...
js对map排序,后端返回有序的LinkedHashMap类型时前端获取后顺序依旧从小到大的解决方法
js对map排序,后端返回有序的LinkedHashMap类型时前端获取后顺序依旧从小到大的解决方法 js对map排序,后端返回有序的LinkedHashMap类型时前端获取后顺序依旧从小到大的解决方法 [{"2020": [{"id": 39,"createTime": &quo…...
JMX vs JFR:谁才是最强大的JVM监控利器?
大家好,我是小米!今天我们来聊一聊JVM监控系统,特别是关于JMX和JFR的使用。你是否有过在线上应用出现性能问题时,无法准确获取关键指标的困扰呢?那么,不妨听听我给大家带来的解决方案。 什么是JMX 首先&a…...
Laravel Collection 基本使用
创建集合 为了创建一个集合,可以将一个数组传入集合的构造器中,也可以创建一个空的集合,然后把元素写到集合中。Laravel 有collect()助手,这是最简单的,新建集合的方法。 $collection collect([1, 2, 3]);默认情况下…...
JUC并发编程19 | 读写锁
有一些关于锁的面试题: 你知道 Java 里面有哪些锁?读写锁的饥饿问题是什么?有没有比读写锁更快的锁?StampedLock知道嘛?(邮戳锁/票据锁)ReentrantReadWriteLock 有锁降级机制? Ree…...
springboot_maven项目怎么引入mybatis
在pom.xml文件中添加mybatis和mybatis-spring-boot-starter的依赖 org.mybatis mybatis ${mybatis.version} org.mybatis.spring.boot mybatis-spring-boot-starter ${mybatis.spring.version} 配置mybatis 在application.properties(或application.yml࿰…...
JAVA8的新特性——lambda表达式
JAVA8的新特性——lambda表达式 此处,我们首先对于Java8的一些特性作为一个简单介绍 Java 8是Java编程语言的一个重要版本,于2014年发布。Java 8引入了许多新特性和改进,以提高开发效率和性能。以下是Java 8的一些主要新特性: Lam…...
算法修炼之练气篇——练气六层
博主:命运之光 专栏:算法修炼之练气篇 前言:每天练习五道题,炼气篇大概会练习200道题左右,题目有C语言网上的题,也有洛谷上面的题,题目简单适合新手入门。(代码都是命运之光自己写的…...
利用GPU并行计算beta-NTI,大幅减少群落构建计算时间
1 先说效果 18个样本,抽平到8500条序列,4344个OTUs,计算beta-NTI共花费时间如下。如果更好的显卡,更大的数据量,节约的时间应该更加可观。 GPU(GTX1050):1分20秒 iCAMP包 的bNTIn.p(…...
Shiro框架漏洞分析与复现
Shiro简介 Apache Shiro是一款开源安全框架,提供身份验证、授权、密码学和会话管理。Shiro框架直观、易用,同时也能提供健壮的安全性,可以快速轻松地保护任何应用程序——从最小的移动应用程序到最大的 Web 和企业应用程序。 1、Shiro反序列…...
(数字图像处理MATLAB+Python)第七章图像锐化-第一、二节:图像锐化概述和微分算子
文章目录 一:图像边缘分析二:一阶微分算子(1)梯度算子A:定义B:边缘检测C:示例D:程序 (2)Robert算子A:定义B:示例C:程序 &a…...
C# | 内存池
内存池 文章目录 内存池前言什么是内存池内存池的优点内存池的缺点 实现思路示例代码结束语 前言 在上一篇文章中,我们介绍了对象池的概念和实现方式。对象池通过重复利用对象,避免了频繁地创建和销毁对象,提高了系统的性能和稳定性。 今天我…...
程序设计入门——C语言2023年5月10日
程序设计入门——C语言 1、window下安装gcc 课程来源:链接: 浙江大学 翁恺 程序设计入门——C语言 学习日期:2023年5月10日 1、window下安装gcc 如果想让gcc在windows下运行,需要将gcc,及对于的lib包,都安装到window…...
【2023华为OD笔试必会25题--C语言版】《03 单入口空闲区域》——递归、数组、DFS
本专栏收录了华为OD 2022 Q4和2023Q1笔试题目,100分类别中的出现频率最高(至少出现100次)的25道,每篇文章包括原始题目 和 我亲自编写并在Visual Studio中运行成功的C语言代码。 仅供参考、启发使用,切不可照搬、照抄,查重倒是可以过,但后面的技术面试还是会暴露的。✨✨…...
Grafana安装、升级与备份(02)
一、安装Grafana软件包 Grafana部署非常简单,直接使用yum命令从官网拉到安装再启动就可以了,本次使用的grafana版本为9.5.0 官网下载地址:Download Grafana | Grafana Labs # wget yum install -y https://dl.grafana.com/oss/release/grafana-9.5.0-1.x86_64.rpm # yum …...
【2023华为OD笔试必会25题--C语言版】《10 相同数字的积木游戏》——数组
本专栏收录了华为OD 2022 Q4和2023Q1笔试题目,100分类别中的出现频率最高(至少出现100次)的25道,每篇文章包括原始题目 和 我亲自编写并在Visual Studio中运行成功的C语言代码。 仅供参考、启发使用,切不可照搬、照抄,查重倒是可以过,但后面的技术面试还是会暴露的。✨✨…...
awk命令编辑
awk工作原理 逐行读取文本,默认以空格或tab键分隔符进行分隔,将分隔所得的各个字段保存到内建变量中,并按模式或者条件执行编辑命令。 sed命令常用于一整行的处理,而awk比较倾向于将一行分成多个“字段”然后再进行处理。awk信息…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
[ICLR 2022]How Much Can CLIP Benefit Vision-and-Language Tasks?
论文网址:pdf 英文是纯手打的!论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误,若有发现欢迎评论指正!文章偏向于笔记,谨慎食用 目录 1. 心得 2. 论文逐段精读 2.1. Abstract 2…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
[大语言模型]在个人电脑上部署ollama 并进行管理,最后配置AI程序开发助手.
ollama官网: 下载 https://ollama.com/ 安装 查看可以使用的模型 https://ollama.com/search 例如 https://ollama.com/library/deepseek-r1/tags # deepseek-r1:7bollama pull deepseek-r1:7b改token数量为409622 16384 ollama命令说明 ollama serve #:…...
Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)
引言 工欲善其事,必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后,我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集,就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...
