05 - 启动时序与性能全景
维度 E:从时间轴与性能视角,梳理
SettingsApplication冷启动完整时序、线程模型、耗时分布、风险点与优化方向 关联:启动慢白屏分析-20260626.md(bugreport 实测权威来源)
一、完整启动时序
sequenceDiagram participant Zygote as Zygote participant Main as 主线程 participant ASYNC as ASYNC线程池<br/>ThreadPoolUtils.ASYNC participant Disp as AppStartTaskDispatcher participant MainTask as MainThreadStartTask participant AsyncTask as AsyncThreadStartTask participant Car as Car服务 Zygote->>Main: fork 进程 activate Main Main->>Main: attachBaseContext (mApp=this) Main->>Main: BaseApplication.onCreate<br/>(initGlobalViewModel) Main->>Main: DfxManager.init Main->>Main: checkAppMatchRom Main->>Main: AppLifecycleTracker 注册 Main->>Main: AutoDensityConfig.init Main->>Main: initLogging (MLog) rect rgb(200, 220, 240) Note over Main,ASYNC: onCreate 启动调度器 Main->>Disp: new + setMain + setAsync + start() Disp->>Disp: new CountDownLatch(1) par 并行启动 Disp->>ASYNC: execute(AsyncThreadStartTask) activate ASYNC AsyncTask->>AsyncTask: SettingsTrack 4ms AsyncTask->>AsyncTask: VoiceAssist 6ms AsyncTask->>AsyncTask: 账号同步 5ms AsyncTask->>AsyncTask: VoiceSearch 0ms AsyncTask->>Car: initHudConfig 17ms AsyncTask->>AsyncTask: Link+MQTT+AudioControl 19ms AsyncTask->>AsyncTask: TrackTrigger / UserSwitchCleaner Note over ASYNC: 异步总 ~61ms(注释) AsyncTask->>Disp: markFinish → countDown() deactivate ASYNC and Disp->>MainTask: run() activate Main MainTask->>MainTask: ActivityLifecycleCallbacks<br/>(Intent 拦截) MainTask->>Car: 配置字块 52ms(注释)<br/>CarProperty 注册~31ms(实测) MainTask->>Car: initConnection<br/>蓝牙188ms+热点22ms(实测) MainTask->>MainTask: Router.init (反射) Note over Main: 主线程实测 247ms<br/>(注释标 71ms) deactivate Main end Disp->>Disp: await(1000ms) alt 正常(异步先完成) ASYNC-->>Disp: latch 归零,返回 else 超时(异步>1000ms) Note over Disp: 强制返回,异步继续后台跑 end end Main->>Main: Log "onCreate finish" deactivate Main Note over Main,ASYNC: onCreate 返回后,二次派发任务仍在跑 Main->>ASYNC: initInAsync (License/MisDevice/儿童座椅) ASYNC->>ASYNC: refreshModeList / updateAvmCarProperties
二、线程模型
2.1 三类执行域
graph TB subgraph Main["主线程(受 await 阻塞)"] M1[BaseApplication.onCreate] M2["前置依赖<br/>DfxManager/checkAppMatchRom<br/>AppLifecycleTracker/AutoDensity/initLogging"] M3["MainThreadStartTask.execute<br/>实测247ms★"] M4[await 阻塞 ≤1000ms] end subgraph Async["ASYNC 线程池(受 latch 约束)"] A1["AsyncThreadStartTask.execute<br/>~61ms(注释)"] A2[→ countDown 释放 latch] end subgraph Blind["二次派发盲区(不受 latch 约束)"] B1["MainThreadStartTask.initInAsync<br/>License绑定/MisDevice/儿童座椅"] B2["refreshModeList"] B3["updateAvmCarProperties"] B4["VoiceSearch 加载缓存"] B5["TrackTrigger 打点"] end M1 --> M2 --> M3 --> M4 A1 --> A2 --> M4 M4 --> Done["onCreate finish"] M3 -.->|"execute 内 ASYNC.execute"| B1 A1 -.->|"内部 ASYNC.execute"| B2 A1 -.-> B3 A1 -.-> B4 A1 -.-> B5 classDef hot fill:#ffe1e1,stroke:#cc0000 class M3 hot
2.2 关键发现:二次派发盲区
受 CountDownLatch 约束的只有 AsyncThreadStartTask.execute() 方法体本身。
不受约束的二次派发(在 execute 内部再 ThreadPoolUtils.ASYNC.execute(...) 或 ThreadUtils.postOnBackgroundThread):
MainThreadStartTask.initInAsync()(:80-114):License 绑定、MisDevice、网络共享检查、儿童座椅同步AsyncThreadStartTask内部:SteeringModeViewModel.refreshModeList()(:116)、AvmSwitchSyncHelper.updateAvmCarProperties()(:147)VoiceSearchManager.initSearchManager:异步加载缓存TrackTrigger.init:postOnBackgroundThread
后果:onCreate 返回(甚至首屏渲染)后,这些任务可能仍在跑 → 若访问尚未就绪的资源,存在竞态风险。
2.3 ThreadPoolUtils.ASYNC 线程池
文件:base/settingsBaseLib/.../uitls/ThreadPoolUtils.java:19-22
ThreadPoolExecutor(0, Integer.MAX_VALUE, 60s, SynchronousQueue, "ThreadPoolUtils async thread")
CachedThreadPool 变体:0 核心、无界最大、不缓冲直接移交。无界最大线程数在高并发二次派发时有线程爆炸风险(白皮书历史 ANR 链底曾涉及 ThreadPoolUtils 线程)。
三、耗时瀑布(注释 vs 实测对照)
3.1 主线程耗时对照表(关键)
| 阶段/项 | 代码注释标注 | bugreport 实测(权威) | 差异说明 |
|---|---|---|---|
| 前置依赖(Dfx/Rom/Density/Log) | 未标 | ~30ms | - |
配置字块(:61-68) | 52ms | CarProperty 注册 ~31ms | 实测仅 CarProperty 部分 |
| initConnection(蓝牙+热点+WiFi) | 27ms | 蓝牙 188ms + 热点 22ms ≈ 210ms | 🔴 实测是注释的 7.8 倍 |
| Router.init | 0ms | - | 反射开销未计 |
| 反射 CNFE 噪声 | - | 4ms+/次 | BroadcastSourceInfoHandler |
| MainThreadStartTask 总计 | 71ms | 247ms | 🔴 实测是注释的 3.5 倍 |
实测工况放大因素(白皮书):
- 驾驶员切换触发的新用户冷启动(非常驻进程重启)
- CPU 95°C / thermal level-3,大核砍 17%
- 30+ user14 进程并发抢 AMS 锁(AM binder 528ms)
3.2 异步任务耗时(仅注释,无独立实测)
| 项 | 标注耗时 |
|---|---|
| SettingsTrack | 4ms |
| VoiceAssist | 6ms |
| 账号同步块 | 5ms |
| VoiceSearch | 0ms |
| initHudConfig | 17ms |
| Link+MQTT+AudioControl | 19ms |
| TrackTrigger/UserSwitchCleaner | (含合计) |
| AsyncThreadStartTask 总 | ~61ms |
3.3 Gantt 瀑布
gantt title SettingsApplication 冷启动耗时瀑布(示意,基于注释+实测) dateFormat X axisFormat %L ms section 主线程(实测247ms) 前置依赖 :0, 30 配置字块CarProperty :30, 61 蓝牙initConnection :61, 249 热点WiFi :249, 271 Router反射 :271, 275 await等异步 :275, 276 section ASYNC线程池(注释~61ms) SettingsTrack :30, 34 VoiceAssist :34, 40 账号同步 :40, 45 VoiceSearch :45, 45 initHudConfig :45, 62 Link+MQTT+AudioControl :62, 81 TrackTrigger/UserSwitch :81, 91 countDown :91, 91 section 二次派发盲区(onCreate后) initInAsync-License :276, 360 refreshModeList :91, 200 updateAvmCarProperties :91, 200
主线程 ~276ms vs 异步 ~91ms:异步先完成,countDown 后主线程仍卡在蓝牙初始化。主线程是绝对瓶颈。
四、CountDownLatch 约束模型
文件:AppStartTaskDispatcher.java
// :33 创建 latch(mNeedWaitCount=1,仅 AsyncThreadStartTask)
mCountDownLatch = new CountDownLatch(mNeedWaitCount.get());
// :75 await 阻塞,超时 1000ms
mCountDownLatch.await(mAllTaskWaitTimeOut, TimeUnit.MILLISECONDS);
// :93 异步完成后 countDown
if (ifNeedWait(absStartTask)) mCountDownLatch.countDown();约束范围:
| 受约束(在 execute 方法体内同步执行) | 不受约束(二次派发) |
|---|---|
| SettingsTrack.init | MainThreadStartTask.initInAsync |
| VoiceAssistProvider.initialize | SteeringModeViewModel.refreshModeList |
| 账号同步 init/register | AvmSwitchSyncHelper.updateAvmCarProperties |
| initHudConfig | VoiceSearchManager.loadCacheWidgets |
| Link+MQTT+AudioControl | TrackTrigger(postOnBackgroundThread) |
| TrackTrigger.init 本体 | |
| UserSwitchCleanerManager.addListener | |
| → markAsyncThreadStartTaskFinish → countDown |
五、风险点清单
| # | 风险 | 位置 | 影响 | 触发条件 |
|---|---|---|---|---|
| R1 | 🔴 主线程 CarProperty 同步注册 | MainThreadStartTask:66 / CarPropertyCacheManager:192 | 主线程阻塞;Activity 阶段 44 个 callback 893ms 白屏 | 冷启动/用户切换 |
| R2 | 🔴 蓝牙同步初始化 188ms | MainThreadStartTask.initConnection:196 | 主线程阻塞 | LocalBluetoothManager 反射 |
| R3 | 🟡 CountDownLatch 超时 1000ms | AppStartTaskDispatcher:75 | 异步卡死时主线程阻塞 1s | AsyncTask 卡死/线程池饱和 |
| R4 | 🟡 二次派发盲区 | MainThreadStartTask:80 / AsyncThreadStartTask:116,147 | onCreate 返回后竞态,访问未就绪资源 | 时序竞争 |
| R5 | 🟡 ASYNC 线程池无界 | ThreadPoolUtils:19 | 高并发线程爆炸 | 大量二次派发 |
| R6 | 🟡 run() 无异常捕获 | AbsStartTask:14-17 | execute 抛异常则 countDown 不执行,主线程阻塞至超时 | 任务异常 |
| R7 | 🟢 MQTT/HUD 同步阻塞异步线程 | AsyncThreadStartTask:94,98 | 异步线程响应变慢 | 服务慢 |
六、优化建议(按性价比)
| 方案 | 改动点 | 收益 | 风险 | 优先级 |
|---|---|---|---|---|
| A 治本 | CarPropertyCacheManager.registerPropertyCallback(:192) 扔单线程 executor;onChangeEvent 处 runOnUiThread 切回 | App 31ms→3ms,Activity 893ms→~30ms | 中(确认回调线程语义) | 🔴 高 |
| B 消白屏 | CarPropertyMgrPreferenceController.onPostCreateInternal(:521) 的 setCarManagerCallback 改 DecorView.post{} | Displayed 1675ms→~500ms | 低(首帧用 Application cache 兜底) | 🔴 高 |
| C 主线程减负 | VehiclePermanentListener.init / 蓝牙 getLocalBtManager(188ms) / HotspotUtils(22ms) 挪进 initInAsync 或 AsyncTask | 主线程省 ~240ms | 低-中(回归蓝牙配对/车控可见性) | 🔴 高 |
| D 降低 latch 超时 | WAIT_TIME 1000ms → 300ms | 异常时少阻塞 | 中(需验证异步最长耗时) | 🟡 中 |
| E 收编二次派发 | initInAsync 等纳入 latch 约束 | 消除竞态 | 低 | 🟡 中 |
| F 限制线程池 | ASYNC 核心 2-4 + 有界队列 | 防线程爆炸 | 低 | 🟡 中 |
| G run() 加 try-finally | AbsStartTask:14 异常仍 countDown | 防超时阻塞 | 无 | 🟡 中 |
| H 代码卫生 | 删 BroadcastSourceInfoHandler 反射 CNFE;修日志保真 | 代码卫生 | 无 | 🟢 低 |
推荐落地:A + B + C 三刀,主线程阻塞从 ~1.2s 压到 <100ms,Displayed 从 1675ms 降到 ~400-500ms。
⚠️ 方案 A 注意:
registerCallback走子线程后,onChangeEvent落在 CarService binder 接收线程,业务 callback 若假设主线程,需在 dispatch 处统一runOnUiThread。 ⚠️ 方案 C 注意:initConnection注释称「必须主线程,否则黑屏」(蓝牙配对异常),挪异步前需与蓝牙模块确认回归。
七、与「启动慢白皮书」的关联
| 白皮书发现 | 本全景对应 |
|---|---|
| Application.onCreate 主线程阻塞 247ms | MainThreadStartTask 实测(注释 71ms) |
| 68 个 CarProperty 注册(Application 阶段)31ms | VehiclePermanentListener.init:66 |
| 44 个 CarProperty 批量注册(Activity 阶段)893ms | CarPropertyCacheManager:192(非启动期,但同根因) |
蓝牙 getLocalBtManager 188ms | MainThreadStartTask.initConnection:196 |
| 历史 09:06 ANR 50s 卡死 | 同「主线程/worker 同步 car binder」模式,ThreadPoolUtils 线程 |
病根一行 CarPropertyCacheManager:192 | 方案 A 改点 |
方案 C 改点 MainThreadStartTask:62,66 | 本全景 R1/R2 |
本全景的增量价值:白皮书聚焦 Activity 阶段白屏(893ms),本全景补充了 Application 阶段的完整框架机制、线程模型、二次派发盲区、latch 约束边界 —— 二者互补。
八、关键源码行号索引
| 文件 | 行号 | 说明 |
|---|---|---|
SettingsApplication.java | 47-67 | onCreate 完整流程 |
| 62-65 | dispatcher 构造与启动 | |
AppStartTaskDispatcher.java | 13 | WAIT_TIME=1000 |
| 29-36 | start() | |
| 33 / 75 / 93 | latch 创建/await/countDown | |
AbsStartTask.java | 14-17 | run()(无 try-catch) |
ThreadPoolUtils.java | 19-22 | ASYNC 无界线程池 |
MainThreadStartTask.java | 48 | 类注释「71MS」 |
| 56-77 | execute() | |
| 61-68 | 配置字块(52ms,含 CarProperty 注册) | |
| 72 | initConnection(蓝牙 188ms) | |
| 80-114 | initInAsync(二次派发盲区) | |
| 193-212 | initConnection 实现 | |
AsyncThreadStartTask.java | 64 | 类注释「61MS」 |
| 74-108 | execute() | |
| 116, 147 | 二次派发 ASYNC.execute | |
VehiclePermanentListener.java | 102-107 / 111 | init / registerPropertyCallback |
CarPropertyCacheManager.java | 192 | 🔴 病根:主线程同步 registerCallback |
九、总结
- 时序:进程 fork → attachBaseContext → onCreate 前置 → dispatcher.start() → 并行(MainThreadStartTask 主线程 + AsyncThreadStartTask 异步)→ await → onCreate finish
- 线程模型:主线程 + ASYNC(latch 约束)+ 二次派发盲区(不受约束)
- 瓶颈:主线程
initConnection(蓝牙 188ms)+ CarProperty 注册;注释严重低估耗时(71ms vs 实测 247ms) - 优化:A(CarProperty 异步化,治本)+ B(post 延迟首帧)+ C(蓝牙/热点挪异步)