1. 问题背景
本次验证聚焦以下场景:
- 后台线程异步调用
WebSettings.getDefaultUserAgent() - 主线程在冷启动阶段首次调用
new WebView() - 两者并发进入 WebView provider / Chromium 初始化链
目标不是验证"预热是否一定提速",而是确认:
- 是否存在共享初始化链竞争
- 主线程是否会因此被拖慢或阶段性阻塞
- 是否具备演化为 ANR 的风险
2. 关键修正结论
结合当前所有日志,更准确的结论应为:
getDefaultUserAgent()与首次new WebView()并发时,二者并不是始终"卡死"在WebViewFactory.getProvider()这一行;更真实的表现是:它们会共享同一条 WebView provider / Chromium 初始化链,在不同阶段交错推进,并在部分关键节点出现阶段性等待、锁竞争或串行化,进而放大主线程耗时。
也就是说,问题本质更接近:
- 交错执行
- 阶段性阻塞
- 共享初始化链导致主线程长卡顿
而不是:
- 两个线程永久互锁
- 一直完全卡死在
WebViewFactory.getProvider()
3. 验证方式
统一实验模式:
EXPERIMENT_MODE = CONCURRENT- 冷启动首次进入
MainActivity - 在
new WebView()前触发后台WebSettings.getDefaultUserAgent() - 通过 watchdog 在
100ms / 200ms / 500ms采样:- 主线程栈
- UA 线程栈
- 当前阻塞时长
- UA 线程状态
关键日志关键词:
WebWarmVerifywatchdog_triggerthread_dump role=mainthread_dump role=ua
4. 测试设备与配置


4.1 模拟器配置
| 设备名 | 系统版本 | 镜像/ABI | 启动方式 | 资源配置 | 配置定位 |
|---|---|---|---|---|---|
Pixel_API25_7.1.1 |
API 25 / Android 7.1.1 |
Google Play x86 |
Cold Boot |
CPU 2核 / RAM 2GB / Graphics Automatic |
问题复现配置 |
Pixel3a_API29_WebView |
API 29 / Android 10 |
Google Play x86_64 |
Cold Boot |
CPU 2核 / RAM 2GB / Graphics Automatic |
问题复现配置 |
Medium Phone API 36 |
API 36 / Android 16 |
Google Play x86_64 |
Cold Boot |
CPU 2核 / RAM 2GB / Graphics Automatic |
问题复现配置 |
说明:
- 上述资源配置用于放大问题、验证机制。
- 不完全等同真实量产机参数,尤其高版本模拟器更偏"保守压测配置"。
- 因此更适用于证明风险存在,而非代表所有真实设备的绝对耗时。
4.2 真机
| 设备 | 系统 | 说明 |
|---|---|---|
| Xiaomi 真机 | Android 16 | 用于补充真实设备行为验证 |
5. 总体观察
所有环境下都能看到以下共同现象:
- 后台
getDefaultUserAgent()与主线程new WebView()明确重叠发生。 - 二者都会进入
WebViewFactory.getProvider()及其后续 provider / Chromium 初始化路径。 - 主线程有时会短暂
BLOCKED at WebViewFactory.getProvider()。 - 更多时候,主线程会继续向后推进,进入:
getProviderClass()loadNativeLibrary()WebViewChromiumFactoryProviderAwBrowserProcessContentMainAwContents
- UA 线程也会在不同阶段交替处于:
RUNNABLEBLOCKEDWAITING
这表明当前问题更像:
共享初始化链上的交错推进 + 局部阻塞
而不是单点永久死锁
6. 分设备结论
6.1 API 25 / Android 7.1.1 模拟器
典型现象:
- 主线程出现在:
WebViewFactory.getProvidergetProviderClassWebViewLibraryLoader.loadNativeLibraryWebViewChromiumFactoryProviderAwBrowserProcess
- UA 线程出现在:
WebSettings.getDefaultUserAgentWebViewFactory.getProviderWebViewChromiumFactoryProvider.getStatics
结论:
- 老版本系统下已明确复现共享初始化链竞争
- 主线程阻塞与后续 Chromium 初始化交错存在
- 问题容易被放大,属于高风险启动卡顿场景
6.2 API 29 / Android 10 模拟器
典型现象:
- 多次抓到主线程:
BLOCKED at WebViewFactory.getProviderWAITING in WebViewChromiumFactoryProvider.<init>SharedPreferencesImpl.awaitLoadedLocked
- 同时 UA 线程位于:
getDefaultUserAgentgetProviderWebViewChromiumFactoryProvider.getStatics
结论:
API 29是证据最强的模拟器环境- 已稳定证明:
- 存在 provider 入口竞争
- 存在 provider 初始化内部等待
- 存在 provider 之后的 Chromium 启动串行化
- 这台设备可作为核心证明样本
6.3 API 36 / Android 16 模拟器
典型现象:
- 主线程多次:
BLOCKED at WebViewFactory.getProvider- 或进入
getProviderClass / loadNativeLibrary / ResourcesManager / AwBrowserProcess / AwContents
- UA 线程同时:
getDefaultUserAgentgetProvidergetProviderClassloadNativeLibraryResourcesManager.registerResourcePaths
结论:
- 高版本系统同样存在该问题
- 说明问题不是老系统特有,也不是单版本偶发
- 高版本上依然会出现明显主线程长卡顿
6.4 Android 16 真机
真机日志体现出两个层次:
A. 常规样本
多次出现:
getDefaultUserAgent_ms ≈ 69ms ~ 73msnewWebView_ms ≈ 85ms ~ 91ms- 未触发 watchdog
- 但仍伴随:
onStart took 451ms ~ 487msSkipped 79+Davey 741ms ~ 782ms
说明:
- 并发存在
- 但不是每次都严重到抓到竞争现场
- 真机上该问题具有波动性
B. 放大样本
例如首条真机样本:
getDefaultUserAgent_ms = 177msnewWebView_ms = 193ms- 触发 watchdog
- 主线程位于:
BrowserStartupControllerImplAwBrowserProcessWebViewChromium.init
- UA 线程位于:
CountDownLatch.awaitWebViewChromiumFactoryProvider$StaticsAdapter.getDefaultUserAgent
说明:
- 真机上也可以抓到共享启动链的交错等待
- 只是相比模拟器,真机更常表现为:
- 部分样本较轻
- 部分样本明显放大
- 更像"间歇性长尾风险"
结论:
- 真机证据支持:问题真实存在
- 但真机更强调"有风险、可放大、非每次都重现到同一强度"
7. 量化表现
结合三台模拟器和真机,当前观察到的范围如下:
| 指标 | 观察结果 |
|---|---|
getDefaultUserAgent_ms |
数十毫秒到 2 秒以上 |
newWebView_ms |
数十毫秒到 2 秒以上 |
dtSinceOnCreate |
从百毫秒到 3 秒以上 |
Skipped frames |
多次高数量掉帧 |
Davey |
从 700ms 到数秒 |
说明:
- 该问题不是"轻微波动"
- 在放大场景下已经能形成秒级主线程长卡顿
- 真机上虽然不一定每次都放大,但已经存在明确长尾风险
8. 统一技术结论
综合所有数据,当前最准确的结论是:
- 后台
WebSettings.getDefaultUserAgent()与主线程首次new WebView()并发时,确实会共享同一条 WebView provider / Chromium 初始化链。 - 两者并不是始终卡死在
WebViewFactory.getProvider();更常见的表现是:- 在
getProvider入口存在阶段性阻塞 - 随后在 provider / classloader / native library / Chromium startup /
AwContents等阶段交错推进
- 在
- 主线程会在这条链路中被显著拖慢,部分样本可出现明显阻塞。
- UA 线程同时处于同一链路的不同阶段,证明共享初始化链竞争真实存在。
- 该现象在
API 25、API 29、API 36以及 Android 16 真机上均可观察到,因此不是单一版本、单一设备或单一 ROM 的问题。
9. ANR 风险结论
当前数据足以证明:
- 存在真实竞争
- 存在主线程阻塞或长卡顿
- 存在明显掉帧和长尾样本
- 具备演化为 ANR 的现实风险
但当前仍不能写成:
- "已经证明必然 ANR"
- "已经采到明确 ANR trace"
因为目前尚缺少:
ANR in com.kuen.beautifulchinaInput dispatching timed out/data/anr/对应主线程 trace
因此建议最终表述为:
已证明
getDefaultUserAgent()与首次new WebView()并发时,会引发共享 WebView provider / Chromium 初始化链上的交错执行与阶段性竞争,能够显著拖慢主线程;在弱环境、冷启动或系统负载较高时可形成秒级长卡顿,具备演化为 ANR 的高风险。
10. 风险定级建议
建议定级为:
- 机制风险:高
- 启动卡顿风险:高
- 长尾稳定性风险:高
- ANR 演化风险:高
11. 整改建议
建议避免以下场景重叠发生:
- 后台异步
getDefaultUserAgent() - 冷启动关键路径中的首次
new WebView()
建议优化方向:
- 不要让
getDefaultUserAgent()与首次new WebView()在冷启动阶段并发发生。 - 若必须预取 UA,应与首次 WebView 创建做时序隔离。
- 若业务必须在冷启动早期使用 WebView,应避免额外后台线程同时触发 WebView provider 初始化。
- 后续可补充:
- 真机稳定场景复测
- 弱机型验证
- ANR trace 采样
12. 总结
本次在
API 25、API 29、API 36三台冷启动模拟设备,以及 Android 16 真机上进行了验证。结果表明:后台WebSettings.getDefaultUserAgent()与主线程首次new WebView()并发时,会共享同一条 WebView provider / Chromium 初始化链。二者并不是始终卡死在WebViewFactory.getProvider(),而是在 provider、classloader、native library、Chromium startup、AwContents等阶段交错推进,并在关键节点发生阶段性阻塞或串行化。实验中多次抓到主线程阻塞于WebViewFactory.getProvider(),后台 UA 线程同时位于getDefaultUserAgent -> getProvider / getProviderClass / loadNativeLibrary / WebViewChromiumFactoryProvider等路径,说明该并发场景会真实拖慢主线程。该问题已在多版本环境中复现,伴随明显掉帧与长卡顿,属于高风险启动稳定性问题,并具备演化为 ANR 的现实风险。