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信息…...

Pinia和Vuex的区别
Pinia和Vuex都是Vue.js状态管理库 Pinia是一个轻量级的状态管理库,它专注于提供一个简单的API来管理应用程序的状态。 相比之下,Vuex是一个更完整的状态管理库,它提供了更多的功能,比如模块化、插件和严格模式等。 Pinia是基于V…...

《C++高并发服务器笔记——第四章Linux网络编程》
计算机网络等相关知识可以去小林coding进行巩固(点击前往) 《C高并发服务器笔记——第四章》 4.1、网络结构模式1.C/S结构①C/S结构简介②C/S结构优点③C/S结构缺点 2.B/S结构①B/S结构简介②B/S结构优点③B/S结构缺点 4.2和4.3、MAC地址、IP地址、端口…...

NFS服务器搭建(案例)
目录标题 第一个问题1.安装软件包2.进入配置文件进行定义,并创建对应的资源文件3.客户端进行挂载,并查看挂载信息,修改挂载权限4.客户端查看挂载的信息 第二个问题1.服务端配置文件进行定义,并创建对应资源文件2.客户端进行挂载3.…...

ubuntu 22.04 安装 Docker Desktop 及docker介绍
目录 一、Docker Desktop 安装 1、我们先去官网下载安装包 2、Install Docker Desktop on Ubuntu 3、Launch Docker Desktop 二、Docker 介绍 什么是docker 如何使用docker docker是如何工作的 docker build docker run docker pull 一、Docker Desktop 安装 1、我们先…...

微前端中的应用隔离是什么,一般是怎么实现的?
微前端中的应用隔离是什么,一般是怎么实现的? 前言一、iframe 隔离二、Web Components三、JavaScript 沙箱隔离四、Shadow DOM 隔离总结 前言 微前端中的应用隔离是指将不同的微前端应用程序隔离开来,以确保它们之间不会相互影响或干扰。这种隔离可以通…...

【python pandas】合并文件并剔除重复数据
1.背景 工作中需要处理多个文件,每个文件里面有重复的数据,剔除重复数据,保留最新的数据 2.代码: import pandas as pd import osdl [] #person_list是文件路径 for i in range(person_list_len):#把文件df全部集合进列表dldl.a…...

Spellman高压电源X射线发生器维修XRB160PN480X4593
spellman高压发生器维修VMX40P5X4629;Spellman X射线发生器维修X4593系列 X射线源维修。 Spellman所拥有的变频器架构可以使高压电源获得高利用率的效率和功率密度。固体密封的高压模块进一步减少了尺寸和重量。 基于表面贴装控制电路的数字信号处理器提供通讯接口…...

msvcr120.dll丢失怎样修复?msvcr120.dll丢失修复的四个方法
打开软件跟游戏提示msvcr120.dll丢失,无法执行此代码怎么办?刚刚遇到这个问题,我都无从下手。家人们,你是不是也被这个问题也困扰过。msvcr120.dll是什么文件呢?经过我一个下午的时间研究,终于搞清楚了&…...

马哈鱼SQLFLow数据流生成介绍
马哈鱼数据血缘分析器是当前最流行的数据血缘关系(data lineage)管理工具之一,它是一种通过分析SQL脚本来自动发现数据流向的工具。它通过生成一个简洁的图表来显示数据仓库中表/视图和列之间的数据流。支持超过20种流行的数据库,包括 bigquery, couchba…...

使用 MVC 模式,实现简单登录功能 (Kotlin)
先放效果图: 第一张是登录页面效果图。用户输入登录名和密码,经过后台的非空验证和固定值验证,跳转到首页 第二张是首页效果图。用户点击 “update” 显示用户名和密码 这里的用户名和密码是后台设置的固定值,整体的登录逻辑特别…...