最近发现手机部分 APP 加载时一直转圈打不开,还有一部分收不到推送通知,排查后定位到 Google FCM 连接失败,在此记录一下整个排查过程。

获取连接状态信息

拨号 *#*#426#*#* 可以查看 FCM 的连接域名、端口以及连接状态等信息。

通过 ADB 排查

为方便操作,通过 ADB 连接手机来敲命令(直接在手机上输入实在太费劲)。注意需要给 adbdcom.android.shell 授予 root 权限。

# 首先排查 DNS 解析
nslookup mtalk.google.com
# 排查网络连通性
ping mtalk.google.com
# 排查端口连通性
telnet mtalk.google.com 5228

DNS、网络、端口三项检测均无异常,这就很奇怪了,于是决定抓包看看。

tcpdump -i any host mtalk.google.com and port 5228

抓包后发现没有任何出站流量,进一步检查防火墙规则:

iptables -vnL
ip6tables -vnL

输出中注意到一条名为 zte_fw_gms 的链,内容如下:

Chain zte_fw_gms (1 references)
 pkts bytes target     prot opt in     out     source               destination
    0     0 ACCEPT     all  --  *      *       0.0.0.0/0            0.0.0.0/0            STRING match  "services.googleapis.cn" ALGO name bm
    0     0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 10343
    0     0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 10249
    0     0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 99910343

这条链看起来很可疑。

iptables -Z                                                # 清空计数器,重新观察
iptables -L zte_fw_gms -n --line-numbers -v                # 再次查看,发现 UID 10343 的计数在上涨
iptables -R zte_fw_gms 2 -m owner --uid-owner 10343 -j ACCEPT   # 将 DROP 改为 ACCEPT,FCM 状态随即变为 connected
netstat -antulp | grep 5228                                # TCP 连接已建立 ESTABLISHED
dumpsys package | grep 10343                               # 查看对应包名,确认无误

至此问题定位完成:FCM 服务被防火墙规则阻断,导致依赖 GMS 的应用无法正常接收推送。

其实直接执行 iptables -F 也能临时解决,但这种方式并不安全。需要注意的是,手机重启后防火墙规则会恢复,需要重新修改或清理。理论上可以通过 KernelSU 的模块机制实现开机自动清理。

写了一个小模块

其实可以通过 Web UI 对规则进行持久化管理,做成一个 iptables 管理模块,支持增删改查以及备份还原。不过考虑到网卡名、IP 变化等因素可能导致规则还原失败,目前还没有太好的思路,只能采用简单粗暴的方式做规则清理。

https://github.com/ydzydzydz/FirewallCleaner